كيفية استخدام App Engine blobstore (الوحدة 15)

1. نظرة عامة

تهدف سلسلة الدروس التطبيقية حول الترميز بدون خادم (البرامج التعليمية العملية) والفيديوهات ذات الصلة إلى مساعدة مطوّري Google Cloud الذين لا يستخدمون خوادم على تحديث تطبيقاتهم من خلال إرشادهم خلال عملية واحدة أو أكثر من عمليات نقل البيانات، بعيدًا عن الخدمات القديمة في المقام الأول. يؤدي ذلك إلى تسهيل حمل التطبيقات وتوفير المزيد من الخيارات والمرونة، ما يتيح لك الدمج مع مجموعة أكبر من منتجات Cloud والوصول إليها والترقية بسهولة إلى الإصدارات الأحدث باللغات. مع تركيزنا في البداية على مستخدمي Cloud الأوائل، لا سيما مطوّري App Engine (البيئة العادية)، فإنّ هذه السلسلة واسعة بما يكفي لتشمل أنظمة أساسية أخرى بدون خادم، مثل Cloud Functions وCloud Run أو أي منصة أخرى إن وُجدت.

تشرح هذه الوحدة التطبيقية حول الترميز في الوحدة 15 كيفية إضافة استخدام App Engine blobstore إلى نموذج التطبيق من الوحدة 0. وبعد ذلك، ستصبح جاهزًا لنقل هذا الاستخدام إلى Cloud Storage بعد ذلك في الوحدة 16.

ستتعرَّف على كيفية إجراء ما يلي:

  • إضافة استخدام واجهة برمجة التطبيقات أو المكتبة في App Engine Blobstore
  • تخزين عمليات التحميل التي أجراها المستخدم إلى خدمة "blobstore"
  • الاستعداد للخطوة التالية لنقل البيانات إلى Cloud Storage

المتطلبات

استطلاع

كيف ستستخدم هذا البرنامج التعليمي؟

القراءة فقط اقرأها وأكمِل التمارين

كيف تقيّم تجربتك مع Python؟

حديث متوسط بارع

ما هو تقييمك لتجربتك في استخدام خدمات Google Cloud؟

حديث متوسط بارع

2. الخلفية

لنقل البيانات من واجهة App Engine Blobstore API، يمكنك إضافة استخدامه إلى تطبيق App Engine الأساسي الحالي ndb من الوحدة 0. يعرض نموذج التطبيق آخر عشر زيارات للمستخدم. نحن بصدد تعديل التطبيق لمطالبة المستخدم النهائي بتحميل عنصر (ملف) يقابل "الزيارة". إذا كان المستخدم لا يرغب في القيام بذلك، فهناك "تخطي" الخيار. بغض النظر عن قرار المستخدم، تعرض الصفحة التالية النتائج نفسها التي يعرضها التطبيق من الوحدة 0 (والعديد من الوحدات الأخرى في هذه السلسلة). من خلال تنفيذ عملية دمج App Engine blobstore هذه، يمكننا نقل البيانات إلى Cloud Storage في الدرس التطبيقي التالي حول الترميز (الوحدة 16).

يوفر App Engine إمكانية الوصول إلى نظامي إنشاء نماذج Django وJinja2، والأمر الذي يميز هذا المثال (إلى جانب إضافة إمكانية الدخول إلى Blobstore) هو التبديل من استخدام Django في الوحدة 0 إلى Jinja2 هنا في الوحدة رقم 15. إنّ نقل إطارات عمل الويب من webapp2 إلى Flask هو خطوة رئيسية في تحديث تطبيقات App Engine. يستخدم الإصدار الأحدث Jinja2 كنظام إنشاء النماذج التلقائي، لذلك نبدأ بالتقدّم في هذا الاتجاه من خلال تنفيذ Jinja2 مع الاستمرار في استخدام webapp2 للوصول إلى Blobstore. بما أنّ Flask تستخدم Jinja2 بشكل تلقائي، لن يكون مطلوبًا إجراء أيّ تغييرات على النموذج في الوحدة 16.

3- الإعداد/التمهيد

قبل أن نصل إلى الجزء الرئيسي من البرنامج التعليمي، قم بإعداد مشروعك والحصول على الرمز ونشر التطبيق الأساسي للبدء بكود يعمل.

1. إعداد المشروع

إذا نشرت تطبيق الوحدة 0 من قبل، نوصيك بإعادة استخدام نفس المشروع (والرمز). ويمكنك بدلاً من ذلك إنشاء مشروع جديد تمامًا أو إعادة استخدام مشروع حالي آخر. عليك التأكّد من أنّ المشروع يتضمّن حساب فوترة نشطًا ومن تفعيل App Engine.

2. الحصول على نموذج تطبيق أساسي

ويتمثّل أحد المتطلّبات الأساسية لهذا الدرس التطبيقي حول الترميز في أن يكون لديك تطبيق نموذجي للوحدة 0 صالح. وإذا لم يكن متوفّرًا لديك، يمكنك الحصول عليه من الوحدة 0 "بدء" (الرابط أدناه). يرشدك هذا الدرس التطبيقي في كل خطوة، إلى الختام بتعليمة برمجية تشبه ما هو موجود في الوحدة 15 "FINISH" المجلد.

يجب أن يبدو دليل ملفات بدء الوحدة 0 على النحو التالي:

$ ls
README.md               index.html
app.yaml                main.py

3- (إعادة نشر التطبيق الأساسي)

إليك الخطوات المتبقية لتنفيذ العمل المسبق الآن:

  1. التعرف مرة أخرى على أداة سطر الأوامر gcloud
  2. إعادة نشر نموذج التطبيق باستخدام "gcloud app deploy"
  3. التأكّد من تشغيل التطبيق على App Engine بدون مشكلة

بعد تنفيذ هذه الخطوات بنجاح ورؤية تطبيق الويب يعمل (مع مخرجات مشابهة لما يرد أدناه)، تكون جاهزًا لإضافة استخدام التخزين المؤقت إلى تطبيقك.

a7a9d2b80d706a2b.png

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 واستبدال نماذج Django بنماذج Jinja2. في ما يلي بعض التغييرات التي سنُجريها:

  1. الغرض من الوحدة النمطية os هو إنشاء اسم مسار ملف لنموذج Django. وبما أنّنا بصدد الانتقال إلى Jinja2 حيث تتم معالجة هذه المشكلة، لن تكون هناك حاجة إلى استخدام os بالإضافة إلى عارض نماذج Django، google.appengine.ext.webapp.template، لذلك سنزيلها.
  2. استيراد Blobstore API: google.appengine.ext.blobstore
  3. استيراد معالِجات Blobstore التي تم العثور عليها في إطار عمل webapp الأصلي، وهي غير متوفّرة في webapp2: google.appengine.ext.webapp.blobstore_handlers
  4. استيراد دعم 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)

في ما يلي تمثيل مصوّر للتغييرات التي تمّ إجراؤها حتى الآن:

2270783776759f7f.png

تحميل ملفات الدعم

يتمثل التغيير الأكثر أهمية في الوظائف في دعم عمليات تحميل الملفات، سواء من خلال مطالبة المستخدم بملف، مع إتاحة ميزة "التخطي" أو عرض ملف يتوافق مع زيارة. وكل ذلك جزء من الصورة. في ما يلي التغييرات المطلوبة لإتاحة عمليات تحميل الملفات:

  1. لم يعد طلب المعالِج الرئيسي GET يجلب أحدث الزيارات للعرض. بدلاً من ذلك، تطلب من المستخدم إجراء عملية تحميل.
  2. عندما يرسل المستخدم ملفًا لتحميله أو يتخطّى هذه العملية، يعمل عنصر POST من النموذج على تمرير عنصر التحكّم إلى عنصر UploadHandler الجديد، مشتق من google.appengine.ext.webapp.blobstore_handlers.BlobstoreUploadHandler.
  3. تُجري طريقة POST في UploadHandler عملية التحميل وتطلب store_visit() لتسجيل الزيارة، ثم تؤدّي إلى إعادة التوجيه HTTP 307 لإعادة توجيه المستخدِم إلى "/"، حيث...
  4. يطلب المعالج الرئيسي طريقة POST من أجل (من خلال fetch_visits()) ويعرض أحدث الزيارات. إذا حدد المستخدم "تخطي"، لم يتم تحميل أي ملف، ولكن ستظل الزيارة مسجلة متبوعةً بعملية إعادة التوجيه نفسها.
  5. تتضمن عرض الزيارات الأخيرة حقلاً جديدًا يظهر للمستخدم، ويكون إما "عرض" مرتبطًا تشعبيًا. إذا كان ملف التحميل متاحًا أو "لا شيء" وإلا. تظهر هذه التغييرات في نموذج HTML مع إضافة نموذج تحميل (سنواصل تناول المزيد من المعلومات حول هذا الموضوع قريبًا).
  6. إذا نقر أحد المستخدمين على "العرض" لأي زيارة مع فيديو محمَّل، يتم إرسال طلب GET إلى ViewBlobHandler جديد، مشتق من google.appengine.ext.webapp.blobstore_handlers.BlobstoreDownloadHandler، إما عن طريق عرض الملف في حال توفّر صورة (في المتصفّح إذا كان متوافقًا)، أو طلب التنزيل إن لم يتم تحميله، أو عرض الخطأ HTTP 404 في حال عدم العثور عليه.
  7. بالإضافة إلى الزوج الجديد من فئتَي المعالِجات بالإضافة إلى زوج جديد من المسارات لإرسال حركة المرور إليها، يحتاج المعالج الرئيسي إلى طريقة 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) "عرض كائن الثنائي الكبير" (view 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)

هناك العديد من الطلبات الرئيسية في هذا الرمز الذي أضفناه للتو:

وتمثّل هذه المكالمات الجزء الأكبر من إمكانية استخدام الميزات المُضافة إلى التطبيق. في ما يلي عرض مصوّر للمجموعة الثانية والأخيرة من التغييرات التي تم إجراؤها على "main.py":

da2960525ac1b90d.png

تعديل نموذج HTML

تؤثر بعض تحديثات التطبيق الرئيسي في واجهة المستخدم الخاصة بالتطبيق، وبالتالي تكون التغييرات المقابلة مطلوبة في نموذج الويب، وهما في الواقع:

  1. يجب توفير نموذج تحميل ملف مع 3 عناصر إدخال: ملف وزرّان للإرسال لتحميل الملف وتخطّيه، على التوالي.
  2. تعديل مخرجات الزيارات الأخيرة عن طريق إضافة "مشاهدة" رابط للزيارات ذات تحميل ملف مطابق أو "لا شيء" وإلا.

قبل:

<!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:

8583e975f25aa9e7.png

ويشمل التغيير الأخير أنّ Jinja2 يفضّل نماذجه في مجلد templates، لذا أنشِئ هذا المجلد وانقل index.html بداخله. من خلال عملية النقل الأخيرة هذه، تكون قد أكملت الآن جميع التغييرات اللازمة لإضافة استخدام Blobstore إلى نموذج التطبيق Module 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()، ما يتطلب استيرادًا جديدًا إذا أردت الوصول إلى هذه القيمة، ويمكن استخدامها كبادئة لتنظيم الملفات المحمَّلة. على سبيل المثال، الترتيب حسب نوع الملف:

f61f7a23a1518705.png

لتنفيذ شيء كهذا للصور، على سبيل المثال، سيكون لديك كود مثل هذا مع بعض التعليمات البرمجية التي تتحقق من أنواع الملفات لاختيار اسم الحزمة المطلوب:

ROOT_BUCKET = app_identity.get_default_gcs_bucket_name()
IMAGE_BUCKET = '%s/%s' % (ROOT_BUCKET, 'images')

ستتحقق أيضًا من صحة الصور التي يتم تحميلها باستخدام أداة مثل وحدة imghdr مكتبة Python المعيارية للتأكد من نوع الصورة. أخيرًا، قد تحتاج إلى الحدّ من حجم الفيديوهات التي تحمّلها إذا واجهت جهات مسيئة.

لنفترض كل ما تم القيام به. كيف يمكننا تحديث التطبيق لإتاحة تحديد مكان تخزين الملفات المحمَّلة؟ المفتاح هو تعديل الطلب إلى 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.

256e1ea68241a501.png

6- الملخّص/تنظيف البيانات

يلخّص هذا القسم هذا الدرس التطبيقي حول الترميز من خلال نشر التطبيق، والتأكّد من أنّه يعمل على النحو المطلوب وفي أي نتائج أخرى. بعد التحقّق من صحة التطبيق، نفِّذ أي خطوات تنظيف وفكِّر في الخطوات التالية.

نشر التطبيق والتحقق منه

أعِد نشر تطبيقك باستخدام "gcloud app deploy"، وتأكَّد من أنّ التطبيق يعمل على النحو الموضّح في الإعلانات، والذي يختلف من حيث تجربة المستخدم (UX) عن تطبيق الوحدة 0. هناك شاشتان مختلفتان في تطبيقك الآن، الأولى هي المطالبة بنموذج تحميل ملف الزيارة:

f5b5f9f19d8ae978.pngمن هناك، يمكن للمستخدمين النهائيين تحميل ملف والنقر على "إرسال". أو انقر على "التخطي" عدم تحميل أي شيء في كلتا الحالتين، تكون النتيجة هي شاشة الزيارة الأخيرة، والتي تم دمجها الآن مع "view" (عرض) روابط أو "بدون" بين الطوابع الزمنية للزيارة ومعلومات الزائر:

f5ac6b98ee8a34cb.png

تهانينا على إكمال هذا الدرس التطبيقي حول الترميز بإضافة استخدام App Engine Blobstore إلى نموذج تطبيق الوحدة 0. يجب أن يكون الرمز مطابقًا لما هو موجود في مجلد FINISH (Module 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/images
  • console.cloud.google.com/storage/browser/staging.PROJECT_ID.appspot.com
  • تعتمد روابط مساحة التخزين أعلاه على PROJECT_ID و *LOC*، على سبيل المثال "us". إذا كان التطبيق مستضافًا في الولايات المتحدة الأمريكية

من ناحية أخرى، إذا كنت لا تريد مواصلة استخدام هذا التطبيق أو الدروس التطبيقية الأخرى ذات الصلة لنقل البيانات وأردت حذف جميع البيانات بالكامل، عليك إيقاف مشروعك.

خصوصيّة هذا الدرس التطبيقي حول الترميز

الخدمات المدرَجة أدناه هي خدمات فريدة لهذا الدرس التطبيقي حول الترميز. ارجع إلى وثائق كل منتج لمزيد من المعلومات:

الخطوات التالية

تتناول الوحدة 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. مراجع إضافية

المشاكل/الملاحظات في الدرس التطبيقي حول الترميز

إذا وجدت أي مشاكل في هذا الدرس التطبيقي حول الترميز، يُرجى البحث عن مشكلتك أولاً قبل ملء النموذج. روابط للبحث وإنشاء مشاكل جديدة:

موارد نقل البيانات

يمكن العثور على روابط لمجلدات repo للوحدة 0 (START) والوحدة 15 (FINISH) في الجدول أدناه. يمكن أيضًا الوصول إليها من المستودع الخاص بجميع عمليات نقل البيانات التطبيقية حول الترميز في App Engine، والتي يمكنك استنساخ ملف ZIP أو تنزيله.

Codelab

Python 2

Python 3

الوحدة 0

الرموز البرمجية

لا ينطبق

الوحدة 15 (هذا الدرس التطبيقي حول الترميز)

الرموز البرمجية

لا ينطبق

مراجع على الإنترنت

في ما يلي موارد على الإنترنت قد تكون ذات صلة بهذا البرنامج التعليمي:

App Engine

Google Cloud

Python

الفيديوهات

الترخيص

هذا العمل مرخّص بموجب رخصة المشاع الإبداعي 2.0 مع نسب العمل إلى مؤلف عام.