1. نظرة عامة
تهدف سلسلة الدروس التطبيقية حول الترميز في Serverless Migration Station (دروس تعليمية عملية ذاتية التوجيه) والفيديوهات ذات الصلة إلى مساعدة مطوّري الحوسبة بدون خادم في Google Cloud على تحديث تطبيقاتهم من خلال توجيههم خلال عملية نقل واحدة أو أكثر، وبشكل أساسي الابتعاد عن الخدمات القديمة. يؤدي ذلك إلى جعل تطبيقاتك أكثر قابلية للنقل ويمنحك المزيد من الخيارات والمرونة، ما يتيح لك التكامل مع مجموعة أوسع من منتجات Cloud والوصول إليها والترقية بسهولة أكبر إلى إصدارات اللغات الأحدث. على الرغم من أنّ هذه السلسلة تركّز في البداية على مستخدمي Cloud الأوائل، وبشكل أساسي مطوّري App Engine (البيئة العادية)، إلا أنّها واسعة بما يكفي لتشمل منصات أخرى بدون خادم، مثل Cloud Functions وCloud Run، أو غيرها إن أمكن.
يشرح هذا الدرس التطبيقي حول الترميز في الوحدة 15 كيفية إضافة استخدام App Engine blobstore إلى نموذج التطبيق من الوحدة 0. بعد ذلك، ستكون مستعدًا لنقل هذا الاستخدام إلى Cloud Storage في الوحدة 16.
ستتعرَّف على كيفية إجراء ما يلي:
- إضافة استخدام واجهة برمجة التطبيقات/مكتبة App Engine Blobstore
- تخزين عمليات تحميل المستخدمين إلى خدمة
blobstore - الاستعداد للخطوة التالية لنقل البيانات إلى Cloud Storage
المتطلبات
- مشروع على Google Cloud Platform يتضمّن حساب فوترة نشطًا على Google Cloud Platform
- مهارات أساسية في لغة Python
- معرفة عملية بأوامر Linux الشائعة
- معرفة أساسية بتطوير تطبيقات App Engine ونشرها
- تطبيق App Engine للوحدة 0 يعمل بشكل صحيح (يمكن الحصول عليه من المستودع)
استطلاع الرأي
كيف ستستخدم هذا البرنامج التعليمي؟
كيف تقيّم تجربتك مع Python؟
ما هو تقييمك لتجربة استخدام خدمات Google Cloud؟
2. خلفية
لنقل البيانات من App Engine Blobstore API، أضِف استخدامها إلى تطبيق ndb الأساسي الحالي في App Engine من الوحدة 0. يعرض نموذج التطبيق آخر عشر زيارات للمستخدم. نحن بصدد تعديل التطبيق ليطلب من المستخدم النهائي تحميل ملف يتوافق مع "زيارته". إذا لم يرغب المستخدم في ذلك، يتوفّر خيار "التخطّي". بغض النظر عن قرار المستخدم، تعرض الصفحة التالية الناتج نفسه الذي يعرضه التطبيق من الوحدة 0 (والعديد من الوحدات الأخرى في هذه السلسلة). بعد تنفيذ عملية دمج App Engine blobstore، يمكننا نقل البيانات إلى Cloud Storage في الدرس التطبيقي التالي حول الترميز (الوحدة 16).
يتيح App Engine الوصول إلى أنظمة النماذج Django وJinja2، والشيء الوحيد الذي يجعل هذا المثال مختلفًا (إلى جانب إضافة إمكانية الوصول إلى Blobstore) هو أنّه ينتقل من استخدام Django في الوحدة 0 إلى Jinja2 هنا في الوحدة 15. تتمثل إحدى الخطوات الرئيسية في تحديث تطبيقات App Engine في نقل أُطر عمل الويب من webapp2 إلى Flask. يستخدم الأخير Jinja2 كنظام النماذج التلقائي، لذلك نبدأ في التحرك في هذا الاتجاه من خلال تنفيذ Jinja2 مع البقاء على webapp2 للوصول إلى Blobstore. بما أن Flask يستخدم Jinja2 بشكل افتراضي، فهذا يعني أنه لن تكون هناك حاجة إلى إجراء تغييرات على القالب في الوحدة 16.
3- الإعداد/العمل المسبق
قبل الانتقال إلى الجزء الرئيسي من البرنامج التعليمي، عليك إعداد مشروعك والحصول على الرمز البرمجي ونشر التطبيق الأساسي للبدء برمز برمجي صالح.
1. إعداد المشروع
إذا سبق لك نشر تطبيق الوحدة 0، ننصحك بإعادة استخدام المشروع (والرمز) نفسه. يمكنك بدلاً من ذلك إنشاء مشروع جديد تمامًا أو إعادة استخدام مشروع حالي آخر. تأكَّد من أنّ المشروع يتضمّن حساب فوترة نشطًا وأنّ App Engine مفعَّل.
2. الحصول على نموذج تطبيق أساسي
من المتطلبات الأساسية لهذا الدرس التطبيقي حول الترميز أن يكون لديك نموذج تطبيق الوحدة 0 يعمل. إذا لم يكن لديك، يمكنك الحصول عليه من مجلد "START" في الوحدة 0 (الرابط أدناه). يرشدك هذا الدرس التطبيقي حول الترميز خلال كل خطوة، وينتهي برمز يشبه ما هو موجود في مجلد "FINISH" في الوحدة 15.
- البدء: مجلد الوحدة 0 (Python 2)
- الانتهاء: مجلد الوحدة 15 (Python 2)
- المستودع بالكامل (لاستنساخ ملف ZIP أو تنزيله)
يجب أن يبدو دليل ملفات STARTing للوحدة 0 على النحو التالي:
$ ls README.md index.html app.yaml main.py
3- (إعادة) نشر التطبيق الأساسي
خطوات العمل التمهيدي المتبقية التي يجب تنفيذها الآن:
- التعرّف مجددًا على أداة سطر الأوامر
gcloud - إعادة نشر نموذج التطبيق باستخدام
gcloud app deploy - تأكَّد من أنّ التطبيق يعمل على App Engine بدون مشاكل
بعد تنفيذ هذه الخطوات بنجاح والتأكّد من أنّ تطبيق الويب يعمل (مع نتائج مشابهة لما يلي)، يمكنك إضافة ميزة التخزين المؤقت إلى تطبيقك.

4. تعديل ملفات الإعداد
app.yaml
لا توجد تغييرات جوهرية في إعدادات التطبيق، ولكن كما ذكرنا سابقًا، نحن ننتقل من قوالب Django (الافتراضية) إلى Jinja2، لذا من أجل التبديل، يجب على المستخدمين تحديد أحدث إصدار من Jinja2 متاح على خوادم App Engine، ويمكنك القيام بذلك عن طريق إضافته إلى قسم مكتبات الجهات الخارجية المضمنة في app.yaml.
قبل:
runtime: python27
threadsafe: yes
api_version: 1
handlers:
- url: /.*
script: main.app
عدِّل ملف app.yaml من خلال إضافة قسم libraries جديد كما هو موضّح أدناه:
بعد:
runtime: python27
threadsafe: yes
api_version: 1
handlers:
- url: /.*
script: main.app
libraries:
- name: jinja2
version: latest
لا حاجة إلى تعديل أي ملفات إعداد أخرى، لذا لننتقل إلى ملفات التطبيق.
5- تعديل ملفات التطبيق
عمليات الاستيراد ودعم Jinja2
تتضمّن المجموعة الأولى من التغييرات في main.py إضافة استخدام Blobstore API واستبدال نماذج Django بـ Jinja2. في ما يلي التغييرات التي سيتم إجراؤها:
- الغرض من وحدة
osهو إنشاء اسم مسار ملف لنموذج Django. بما أنّنا سننتقل إلى Jinja2 حيث تتم معالجة ذلك، لم يعُد استخدامosوأداة عرض نماذج Django، أيgoogle.appengine.ext.webapp.template، ضروريًا، لذا ستتم إزالتهما. - استيراد واجهة برمجة التطبيقات Blobstore API:
google.appengine.ext.blobstore - استورِد معالِجات Blobstore المتوفّرة في إطار عمل
webappالأصلي، فهي غير متاحة فيwebapp2:google.appengine.ext.webapp.blobstore_handlers - استيراد دعم Jinja2 من حزمة
webapp2_extras
قبل:
import os
import webapp2
from google.appengine.ext import ndb
from google.appengine.ext.webapp import template
نفِّذ التغييرات الواردة في القائمة أعلاه من خلال استبدال قسم الاستيراد الحالي في main.py بمقتطف الرمز أدناه.
بعد:
import webapp2
from webapp2_extras import jinja2
from google.appengine.ext import blobstore, ndb
from google.appengine.ext.webapp import blobstore_handlers
بعد عمليات الاستيراد، أضِف بعض الرموز البرمجية النموذجية لإتاحة استخدام Jinja2 كما هو محدّد في مستندات webapp2_extras. يغلّف مقتطف الرمز التالي فئة معالج طلبات webapp2 العادية بوظيفة Jinja2، لذا أضِف مجموعة الرموز هذه إلى main.py بعد عمليات الاستيراد مباشرةً:
class BaseHandler(webapp2.RequestHandler):
'Derived request handler mixing-in Jinja2 support'
@webapp2.cached_property
def jinja2(self):
return jinja2.get_jinja2(app=self.app)
def render_response(self, _template, **context):
self.response.write(self.jinja2.render_template(_template, **context))
إضافة إمكانية استخدام Blobstore
على عكس عمليات النقل الأخرى في هذه السلسلة التي نحافظ فيها على وظائف نموذج التطبيق أو مخرجاته متطابقة (أو متطابقة تقريبًا) بدون تغيير (كبير) في تجربة المستخدم، يختلف هذا المثال بشكل جذري عن المعتاد. بدلاً من تسجيل زيارة جديدة على الفور ثم عرض آخر عشر زيارات، سنعدّل التطبيق ليطلب من المستخدم ملفًا لتسجيل زيارته. يمكن للمستخدمين النهائيين بعد ذلك تحميل ملف مطابق أو اختيار "التخطّي" لعدم تحميل أي ملف على الإطلاق. بعد اكتمال هذه الخطوة، ستظهر صفحة "أحدث الزيارات".
يسمح هذا التغيير لتطبيقنا باستخدام خدمة Blobstore لتخزين (وربما عرض لاحقًا) تلك الصورة أو نوع ملف آخر في صفحة الزيارات الأخيرة.
تعديل نموذج البيانات وتنفيذ استخدامه
نحن نخزّن المزيد من البيانات، وتحديدًا نعدّل نموذج البيانات لتخزين معرّف (يُعرف باسم "BlobKey") الملف الذي تم تحميله إلى Blobstore ونضيف مرجعًا لحفظه في store_visit(). بما أنّ هذه البيانات الإضافية يتم عرضها مع كل البيانات الأخرى عند إجراء طلب بحث، يبقى fetch_visits() كما هو.
في ما يلي مقارنة بين ما قبل هذه التعديلات وما بعدها، مع file_blob، وهو ndb.BlobKeyProperty:
قبل:
class Visit(ndb.Model):
'Visit entity registers visitor IP address & timestamp'
visitor = ndb.StringProperty()
timestamp = ndb.DateTimeProperty(auto_now_add=True)
def store_visit(remote_addr, user_agent):
'create new Visit entity in Datastore'
Visit(visitor='{}: {}'.format(remote_addr, user_agent)).put()
def fetch_visits(limit):
'get most recent visits'
return Visit.query().order(-Visit.timestamp).fetch(limit)
بعد:
class Visit(ndb.Model):
'Visit entity registers visitor IP address & timestamp'
visitor = ndb.StringProperty()
timestamp = ndb.DateTimeProperty(auto_now_add=True)
file_blob = ndb.BlobKeyProperty()
def store_visit(remote_addr, user_agent, upload_key):
'create new Visit entity in Datastore'
Visit(visitor='{}: {}'.format(remote_addr, user_agent),
file_blob=upload_key).put()
def fetch_visits(limit):
'get most recent visits'
return Visit.query().order(-Visit.timestamp).fetch(limit)
في ما يلي تمثيل مصوّر للتغييرات التي تم إجراؤها حتى الآن:

إتاحة تحميل الملفات
التغيير الأهم في الوظائف هو إتاحة تحميل الملفات، سواء من خلال مطالبة المستخدم بتحميل ملف أو إتاحة ميزة "التخطّي" أو عرض ملف يتوافق مع زيارة معيّنة. كل ذلك جزء من الصورة. في ما يلي التغييرات المطلوبة لإتاحة تحميل الملفات:
- لم يعُد طلب المعالج الرئيسي
GETيجلب أحدث الزيارات لعرضها. بدلاً من ذلك، يطلب من المستخدم تحميل الملف. - عندما يرسل المستخدم النهائي ملفًا لتحميله أو يتخطّى هذه العملية، ينقل
POSTمن النموذج التحكّم إلىUploadHandlerالجديد، المشتق منgoogle.appengine.ext.webapp.blobstore_handlers.BlobstoreUploadHandler. - تنفّذ طريقة
POSTفيUploadHandlerعملية التحميل، وتستدعيstore_visit()لتسجيل الزيارة، وتُشغّل إعادة توجيه HTTP 307 لإعادة المستخدم إلى "/"، حيث... - تستعلم طريقة
POSTالخاصة بالمعالج الرئيسي عن آخر الزيارات (عبرfetch_visits()) وتعرضها. إذا اختار المستخدم "التخطّي"، لن يتم تحميل أي ملف، ولكن سيتم تسجيل الزيارة متبوعةً بإعادة التوجيه نفسها. - يتضمّن عرض الزيارات الأخيرة حقلاً جديدًا يظهر للمستخدم، إما رابط تشعّبي بعنوان "عرض" إذا كان ملف التحميل متاحًا أو "بلا" في حال عدم توفّره. يتم تنفيذ هذه التغييرات في نموذج HTML إلى جانب إضافة نموذج تحميل (المزيد حول هذا قريبًا).
- إذا نقر مستخدم نهائي على رابط "عرض" لأي زيارة تتضمّن فيديو تم تحميله، يتم إرسال طلب
GETإلىViewBlobHandlerجديد، مشتق منgoogle.appengine.ext.webapp.blobstore_handlers.BlobstoreDownloadHandler، إما لعرض الملف إذا كان صورة (في المتصفّح إذا كان متوافقًا)، أو طلب تنزيله إذا لم يكن كذلك، أو عرض خطأ HTTP 404 إذا لم يتم العثور عليه. - بالإضافة إلى الفئتَين الجديدتَين من المعالِجات والمسارَين الجديدَين لإرسال الزيارات إليهما، يحتاج المعالِج الرئيسي إلى طريقة
POSTجديدة لتلقّي إعادة التوجيه 307 الموضّحة أعلاه.
قبل هذه التعديلات، كان تطبيق الوحدة 0 يتضمّن فقط معالجًا رئيسيًا مع طريقة GET ومسار واحد:
قبل:
class MainHandler(webapp2.RequestHandler):
'main application (GET) handler'
def get(self):
store_visit(self.request.remote_addr, self.request.user_agent)
visits = fetch_visits(10)
tmpl = os.path.join(os.path.dirname(__file__), 'index.html')
self.response.out.write(template.render(tmpl, {'visits': visits}))
app = webapp2.WSGIApplication([
('/', MainHandler),
], debug=True)
بعد تنفيذ هذه التعديلات، أصبح هناك الآن ثلاثة معالجات: 1) معالج التحميل باستخدام طريقة POST، و2) معالج التنزيل "عرض blob" باستخدام طريقة GET، و3) المعالج الرئيسي باستخدام طريقتَي GET وPOST. أجرِ هذه التغييرات لكي يظهر باقي تطبيقك الآن على النحو التالي.
بعد:
class UploadHandler(blobstore_handlers.BlobstoreUploadHandler):
'Upload blob (POST) handler'
def post(self):
uploads = self.get_uploads()
blob_id = uploads[0].key() if uploads else None
store_visit(self.request.remote_addr, self.request.user_agent, blob_id)
self.redirect('/', code=307)
class ViewBlobHandler(blobstore_handlers.BlobstoreDownloadHandler):
'view uploaded blob (GET) handler'
def get(self, blob_key):
self.send_blob(blob_key) if blobstore.get(blob_key) else self.error(404)
class MainHandler(BaseHandler):
'main application (GET/POST) handler'
def get(self):
self.render_response('index.html',
upload_url=blobstore.create_upload_url('/upload'))
def post(self):
visits = fetch_visits(10)
self.render_response('index.html', visits=visits)
app = webapp2.WSGIApplication([
('/', MainHandler),
('/upload', UploadHandler),
('/view/([^/]+)?', ViewBlobHandler),
], debug=True)
هناك العديد من الاستدعاءات الرئيسية في هذا الرمز الذي أضفناه للتو:
- في
MainHandler.get، هناك دعوة إلىblobstore.create_upload_url. يؤدي هذا الطلب إلى إنشاء عنوان URL الذي يرسل النموذجPOSTإليه، ويستدعي معالج التحميل لإرسال الملف إلى Blobstore. - في
UploadHandler.post، هناك دعوة إلىblobstore_handlers.BlobstoreUploadHandler.get_uploads. هذا هو السحر الحقيقي الذي يضع الملف في Blobstore ويعرض معرّفًا فريدًا ومستمرًا لهذا الملف، وهوBlobKey. - في
ViewBlobHandler.get، يؤدي استدعاءblobstore_handlers.BlobstoreDownloadHandler.sendباستخدامBlobKeyلملف إلى جلب الملف وإعادة توجيهه إلى متصفّح المستخدم النهائي
تمثّل هذه الطلبات الجزء الأكبر من الوصول إلى الميزات المضافة إلى التطبيق. في ما يلي تمثيل مصوّر لهذه المجموعة الثانية والأخيرة من التغييرات على main.py:

تعديل نموذج HTML
تؤثر بعض التحديثات على التطبيق الرئيسي في واجهة مستخدم التطبيق (UI)، لذا يلزم إجراء تغييرات مقابلة في قالب الويب، وهما في الواقع:
- يجب توفير نموذج لتحميل الملفات يتضمّن 3 عناصر إدخال: ملف وزرَّي إرسال لتحميل الملف وتخطّيه على التوالي.
- عدِّل ناتج الزيارات الأخيرة من خلال إضافة رابط "عرض" للزيارات التي تتضمّن تحميل ملف مقابل أو "بلا" في الحالات الأخرى.
قبل:
<!doctype html>
<html>
<head>
<title>VisitMe Example</title>
<body>
<h1>VisitMe example</h1>
<h3>Last 10 visits</h3>
<ul>
{% for visit in visits %}
<li>{{ visit.timestamp.ctime }} from {{ visit.visitor }}</li>
{% endfor %}
</ul>
</body>
</html>
نفِّذ التغييرات في القائمة أعلاه لتضمين النموذج المعدَّل:
بعد:
<!doctype html>
<html>
<head>
<title>VisitMe Example</title>
<body>
<h1>VisitMe example</h1>
{% if upload_url %}
<h3>Welcome... upload a file? (optional)</h3>
<form action="{{ upload_url }}" method="POST" enctype="multipart/form-data">
<input type="file" name="file"><p></p>
<input type="submit"> <input type="submit" value="Skip">
</form>
{% else %}
<h3>Last 10 visits</h3>
<ul>
{% for visit in visits %}
<li>{{ visit.timestamp.ctime() }}
<i><code>
{% if visit.file_blob %}
(<a href="/view/{{ visit.file_blob }}" target="_blank">view</a>)
{% else %}
(none)
{% endif %}
</code></i>
from {{ visit.visitor }}
</li>
{% endfor %}
</ul>
{% endif %}
</body>
</html>
توضّح هذه الصورة التعديلات المطلوبة على index.html:

هناك تغيير أخير وهو أنّ Jinja2 يفضّل استخدام النماذج في مجلد templates، لذا أنشئ هذا المجلد وانقل index.html إليه. بهذه الخطوة الأخيرة، تكون قد انتهيت من جميع التغييرات اللازمة لإضافة استخدام Blobstore إلى نموذج تطبيق الوحدة 0.
(اختياري) "تحسين" Cloud Storage
تطوّرت مساحة تخزين Blobstore في النهاية إلى Cloud Storage نفسها. وهذا يعني أنّ عمليات التحميل في Blobstore تظهر في Cloud Console، وتحديدًا في متصفّح Cloud Storage. والسؤال هو أين. الإجابة هي حزمة Cloud Storage التلقائية لتطبيق App Engine. ويكون اسمه هو اسم النطاق الكامل لتطبيق App Engine، PROJECT_ID.appspot.com. هذا مريح للغاية لأن جميع أرقام تعريف المشاريع فريدة، أليس كذلك؟
تؤدي التعديلات التي تم إجراؤها على نموذج التطبيق إلى إسقاط الملفات التي تم تحميلها في هذا المستودع، ولكن يتوفّر للمطوّرين خيار تحديد موقع أكثر تحديدًا. يمكن الوصول إلى الحزمة التلقائية آليًا من خلال google.appengine.api.app_identity.get_default_gcs_bucket_name()، ما يتطلّب عملية استيراد جديدة إذا أردت الوصول إلى هذه القيمة، مثلاً لاستخدامها كبادئة لتنظيم الملفات التي تم تحميلها. على سبيل المثال، الترتيب حسب نوع الملف:

لتنفيذ شيء من هذا القبيل للصور، على سبيل المثال، سيكون لديك رمز مثل هذا مع بعض الرموز التي تتحقق من أنواع الملفات لاختيار اسم الحاوية المطلوب:
ROOT_BUCKET = app_identity.get_default_gcs_bucket_name()
IMAGE_BUCKET = '%s/%s' % (ROOT_BUCKET, 'images')
ستتحقّق أيضًا من صحة الصور التي تم تحميلها باستخدام أداة مثل وحدة imghdr في مكتبة بايثون العادية لتأكيد نوع الصورة. أخيرًا، قد تحتاج إلى تحديد حجم عمليات التحميل في حال وجود جهات سيئة.
لنفترض أنّ كل ذلك قد تم. كيف يمكننا تعديل تطبيقنا ليتيح تحديد مكان تخزين الملفات التي يتم تحميلها؟ يكمن الحلّ في تعديل طلب blobstore.create_upload_url في MainHandler.get لتحديد الموقع المطلوب في Cloud Storage للتحميل من خلال إضافة المَعلمة gs_bucket_name على النحو التالي:
blobstore.create_upload_url('/upload', gs_bucket_name=IMAGE_BUCKET))
بما أنّ هذا التعديل اختياري إذا أردت تحديد مكان حفظ عمليات التحميل، فهو ليس جزءًا من ملف main.py في المستودع. بدلاً من ذلك، يتوفّر بديل باسم main-gcs.py لمراجعته في المستودع. بدلاً من استخدام "مجلد" حزمة منفصل، يخزّن الرمز في main-gcs.py عمليات التحميل في حزمة "الجذر" (PROJECT_ID.appspot.com) تمامًا مثل main.py، ولكنّه يوفّر البنية الأساسية التي تحتاج إليها إذا كنت تريد اشتقاق النموذج إلى شيء أكثر كما هو موضّح في هذا القسم. في ما يلي رسم توضيحي لـ "الاختلافات" بين main.py وmain-gcs.py.

6. الملخّص/التنظيف
يختتم هذا القسم الدرس التطبيقي حول الترميز من خلال نشر التطبيق والتحقّق من أنّه يعمل على النحو المطلوب وفي أي ناتج منعكس. بعد التحقّق من التطبيق، نفِّذ أي خطوات لإزالة البيانات غير الضرورية وفكِّر في الخطوات التالية.
نشر التطبيق والتحقّق منه
أعِد نشر تطبيقك باستخدام gcloud app deploy، وتأكَّد من أنّه يعمل على النحو المُعلن عنه، ويختلف في تجربة المستخدم عن تطبيق الوحدة 0. هناك شاشتان مختلفتان في تطبيقك الآن، الأولى هي طلب نموذج تحميل ملف الزيارة:
من هناك، يمكن للمستخدمين النهائيين تحميل ملف والنقر على "إرسال" أو النقر على "تخطّي" لعدم تحميل أي ملف. في كلتا الحالتين، تكون النتيجة هي شاشة الزيارة الأخيرة، والتي تم تعزيزها الآن بروابط "عرض" أو "بلا" بين الطوابع الزمنية للزيارة ومعلومات الزائر:

تهانينا على إكمال هذا الدرس التطبيقي حول الترميز الذي يضيف استخدام App Engine Blobstore إلى نموذج تطبيق الوحدة 0. من المفترض أن يتطابق الرمز الآن مع ما هو متوفّر في مجلد FINISH (الوحدة 15). يتوفّر أيضًا البديل main-gcs.py في هذا المجلد.
تَنظيم
بنود عامة
إذا انتهيت من العمل في الوقت الحالي، ننصحك بإيقاف تطبيق App Engine لتجنُّب تحمُّل تكاليف الفوترة. ومع ذلك، إذا أردت إجراء المزيد من الاختبارات أو التجارب، فإنّ منصة App Engine توفّر حصة مجانية، ولن يتم تحصيل أي رسوم منك طالما أنّك لا تتجاوز فئة الاستخدام هذه. هذا بالنسبة إلى الحوسبة، ولكن قد تكون هناك أيضًا رسوم لخدمات App Engine ذات الصلة، لذا يُرجى الاطّلاع على صفحة الأسعار لمزيد من المعلومات. إذا كانت عملية النقل هذه تتضمّن خدمات Cloud أخرى، فستتم فوترتها بشكل منفصل. في كلتا الحالتَين، يُرجى الاطّلاع على قسم "تفاصيل خاصة بهذا الدرس التطبيقي حول الترميز" أدناه، إذا كان ذلك منطبقًا.
للكشف الكامل، يؤدي النشر على منصة حوسبة بدون خادم في Google Cloud، مثل App Engine، إلى تحمُّل تكاليف بسيطة لعمليات الإنشاء والتخزين. تتوفّر في Cloud Build حصة مجانية خاصة بها، كما هو الحال في Cloud Storage. ويستهلك تخزين هذه الصورة جزءًا من هذه الحصة. ومع ذلك، قد تكون مقيمًا في منطقة لا تتوفّر فيها هذه الفئة المجانية، لذا عليك الانتباه إلى سعة التخزين المطلوب استخدامها لتقليل التكاليف المحتملة. تشمل "مجلدات" Cloud Storage المحدّدة التي يجب مراجعتها ما يلي:
console.cloud.google.com/storage/browser/LOC.artifacts.PROJECT_ID.appspot.com/containers/imagesconsole.cloud.google.com/storage/browser/staging.PROJECT_ID.appspot.com- تعتمد روابط مساحة التخزين أعلاه على
PROJECT_IDو *LOC*ation، على سبيل المثال، "us" إذا كان تطبيقك مستضافًا في الولايات المتحدة.
من ناحية أخرى، إذا كنت لن تواصل استخدام هذا التطبيق أو الدروس التطبيقية الأخرى ذات الصلة حول الترميز لنقل البيانات وتريد حذف كل شيء بالكامل، يمكنك إيقاف مشروعك.
خاص بهذا الدرس التطبيقي حول الترميز
الخدمات المدرَجة أدناه فريدة لهذا الدرس التطبيقي حول الترميز. يُرجى الرجوع إلى مستندات كل منتج لمزيد من المعلومات:
- تندرج خدمة Blobstore في App Engine ضمن الحصص والحدود القصوى للبيانات المخزَّنة، لذا يُرجى مراجعة ذلك بالإضافة إلى صفحة الأسعار للخدمات المجمّعة القديمة.
- يتم توفير خدمة App Engine Datastore من خلال Cloud Datastore (Cloud Firestore في وضع Datastore) الذي يتضمّن أيضًا فئة مجانية. لمزيد من المعلومات، يُرجى الاطّلاع على صفحة الأسعار.
الخطوات التالية
تتناول الوحدة 16 عملية النقل المنطقية التالية التي يجب وضعها في الاعتبار، حيث توضّح للمطوّرين كيفية النقل من خدمة App Engine Blobstore إلى استخدام مكتبة برامج Cloud Storage. تشمل مزايا الترقية إمكانية الوصول إلى المزيد من ميزات Cloud Storage، والتعرّف على مكتبة برامج تعمل مع التطبيقات خارج App Engine، سواء في Google Cloud أو السُحب الإلكترونية الأخرى أو حتى داخل الشركة. إذا كنت لا تحتاج إلى جميع الميزات المتاحة في Cloud Storage أو كنت قلقًا بشأن تأثيرها في التكلفة، يمكنك مواصلة استخدام App Engine Blobstore.
بعد الوحدة 16، هناك مجموعة كاملة من عمليات النقل الأخرى الممكنة، مثل Cloud NDB وCloud Datastore أو Cloud Tasks أو Cloud Memorystore. تتوفّر أيضًا عمليات نقل بين المنتجات إلى Cloud Run وCloud Functions. يتضمّن مستودع نقل البيانات جميع عيّنات التعليمات البرمجية، ويوفّر روابط إلى جميع الدروس التطبيقية حول الترميز والفيديوهات المتاحة، كما يقدّم إرشادات حول عمليات نقل البيانات التي يجب أخذها في الاعتبار وأي "ترتيب" ذي صلة لعمليات نقل البيانات.
7. مراجع إضافية
مشاكل/ملاحظات حول الدروس التطبيقية حول الترميز
إذا واجهت أي مشاكل في هذا الدرس التطبيقي حول الترميز، يُرجى البحث عن مشكلتك أولاً قبل تقديم بلاغ. روابط للبحث عن مشاكل جديدة وإنشائها:
مراجع لنقل البيانات
يمكن العثور على روابط إلى مجلدات المستودع للوحدة 0 (START) والوحدة 15 (FINISH) في الجدول أدناه. ويمكن أيضًا الوصول إليها من مستودع جميع عمليات نقل الدروس التطبيقية حول الترميز في App Engine الذي يمكنك استنساخه أو تنزيل ملف ZIP منه.
درس تطبيقي حول الترميز | Python 2 | Python 3 |
الوحدة رقم 0 | لا ينطبق | |
الوحدة 15 (هذا الدرس التطبيقي حول الترميز) | لا ينطبق |
مراجع متوفرة على الإنترنت
في ما يلي مراجع على الإنترنت قد تكون ذات صلة بهذا البرنامج التعليمي:
App Engine
- خدمة App Engine Blobstore
- الحصص والحدود القصوى للبيانات المخزَّنة في App Engine
- مستندات App Engine
- بيئة تشغيل Python 2 App Engine (البيئة العادية)
- استخدام مكتبات App Engine المضمّنة في App Engine بلغة Python 2
- معلومات حول أسعار وحصص App Engine
- إطلاق الجيل الثاني من منصة App Engine (2018)
- مقارنة بين منصات الجيلَين الأول والثاني
- دعم طويل الأمد لبيئات التشغيل القديمة
- مستودع نماذج نقل المستندات
- مستودع نماذج نقل البيانات التي يساهم بها المنتدى
Google Cloud
- Python على Google Cloud Platform
- مكتبات برامج Google Cloud Python
- فئة "المجانية دائمًا" في Google Cloud
- حزمة تطوير البرامج (SDK) في Google Cloud (أداة سطر أوامر gcloud)
- جميع مستندات Google Cloud
Python
- أنظمة النماذج Django وJinja2
- إطار عمل الويب
webapp2 - مستندات
webapp2 - روابط "
webapp2_extras" webapp2_extrasمستندات Jinja2
الفيديوهات
- Serverless Migration Station
- Serverless Expeditions
- الاشتراك في قناة Google Cloud Tech
- الاشتراك في قناة Google Developers
الترخيص
هذا العمل مرخَّص بموجب رخصة المشاع الإبداعي 2.0 العامة مع نسب العمل إلى مؤلفه.