1. نظرة عامة
تهدف سلسلة الدروس التطبيقية حول الترميز بدون خادم (البرامج التعليمية العملية) والفيديوهات ذات الصلة إلى مساعدة مطوّري Google Cloud الذين لا يستخدمون خوادم على تحديث تطبيقاتهم من خلال إرشادهم خلال عملية واحدة أو أكثر من عمليات نقل البيانات، بعيدًا عن الخدمات القديمة في المقام الأول. يؤدي ذلك إلى تسهيل حمل التطبيقات وتوفير المزيد من الخيارات والمرونة، ما يتيح لك الدمج مع مجموعة أكبر من منتجات Cloud والوصول إليها والترقية بسهولة إلى الإصدارات الأحدث باللغات. مع تركيزنا في البداية على مستخدمي Cloud الأوائل، لا سيما مطوّري App Engine (البيئة العادية)، فإنّ هذه السلسلة واسعة بما يكفي لتشمل أنظمة أساسية أخرى بدون خادم، مثل Cloud Functions وCloud Run أو أي منصة أخرى إن وُجدت.
تشرح لك هذه الدرس التطبيقي كيفية نقل البيانات من App Engine Blobstore إلى Cloud Storage. هناك أيضًا عمليات نقل بيانات ضمنية من:
webapp2
إطار عمل على الويب إلى Flask (مغطى الوحدة 1)- اتفاقية المطوّرين للنشر على App Engine إلى Cloud NDB للوصول إلى "مخزن البيانات" (تغطّي الوحدة 2)
- Python 2 إلى 3 (التطبيق الذي تم نقله متوافق مع Python 2 وPython 3)
يمكنك الاطّلاع على أي وحدات نقل بيانات ذات صلة للحصول على مزيد من المعلومات خطوة بخطوة.
ستتعرَّف على كيفية إجراء ما يلي:
- إضافة استخدام واجهة برمجة التطبيقات أو المكتبة في App Engine Blobstore
- تخزين عمليات التحميل التي يجريها المستخدم إلى خدمة Blobstore
- الاستعداد للخطوة التالية لنقل البيانات إلى Cloud Storage
المتطلبات
- مشروع Google Cloud Platform مع حساب فوترة نشط على Google Cloud Platform
- المهارات الأساسية في لغة بايثون
- المعرفة العملية بأوامر نظام التشغيل Linux الشائعة
- معرفة أساسية حول تطوير ونشر تطبيقات App Engine
- تطبيق App Engine صالح للوحدة 15: إكمال الدرس التطبيقي حول الترميز للوحدة 15 (يُنصح به) أو نسخ تطبيق الوحدة 15 من المستودع
استطلاع
كيف ستستخدم هذا البرنامج التعليمي؟
كيف تقيّم تجربتك مع Python؟
ما هو تقييمك لتجربتك في استخدام خدمات Google Cloud؟
2. الخلفية
يبدأ هذا الدرس التطبيقي بنموذج تطبيق من الوحدة 15 ويوضّح كيفية نقل البيانات من Blobstore (و NDB) إلى Cloud Storage (وCloud NDB). تتضمن عملية نقل البيانات استبدال الاعتماديات على الخدمات المجمّعة القديمة لـ App Engine، والتي تتيح لك نقل تطبيقاتك إلى نظام أساسي آخر على Cloud بدون خادم أو نظام أساسي آخر للاستضافة إذا كنت ترغب في ذلك.
تتطلب عملية نقل البيانات هذه جهدًا أكبر قليلاً مقارنةً بعمليات نقل البيانات الأخرى في هذه السلسلة. تعتمد Blobstore على إطار عمل تطبيق الويب الأصلي، ولهذا يستخدم نموذج التطبيق إطار عمل webapp2 بدلاً من Flask. يعرض هذا البرنامج التعليمي عمليات النقل إلى Cloud Storage وCloud NDB وFlesk وPython 3.
يستمر التطبيق في تسجيل "زيارات" المستخدمين النهائيين. ويعرض آخر عشرة درسًا، لكن الدرس التطبيقي السابق (الوحدة 15) أضاف وظيفة جديدة لاستيعاب استخدام Blobstore: يطلب التطبيق من المستخدمين النهائيين تحميل عناصر (ملف) تناسب "الزيارة". يمكن للمستخدمين إجراء ذلك أو اختيار "تخطّي" لإيقاف الميزة. وبغض النظر عن قرار المستخدم، تعرِض الصفحة التالية النتائج نفسها التي تعرِضها الأشكال السابقة لهذا التطبيق، مع عرض آخر الزيارات. وهناك جانب آخر يتمثل في أن الزيارات المصحوبة بالعناصر المقابلة لها تعرض "مشاهدة" لعرض عنصر الزيارة. ينفِّذ هذا الدرس التطبيقي حول الترميز عمليات نقل البيانات المذكورة سابقًا مع الحفاظ على الوظائف الموضّحة.
3- الإعداد/التمهيد
قبل أن نصل إلى الجزء الرئيسي من البرنامج التعليمي، لنقم بإعداد مشروعنا، ونحصل على الكود، ثم ننشر التطبيق الأساسي حتى نعرف أننا بدأنا برمز العمل.
1. إعداد المشروع
إذا نشرت تطبيق الوحدة 15 من قبل، نوصي بإعادة استخدام نفس المشروع (والرمز) ويمكنك بدلاً من ذلك إنشاء مشروع جديد تمامًا أو إعادة استخدام مشروع حالي آخر. عليك التأكّد من أنّ المشروع يتضمّن حساب فوترة نشطًا ومن تفعيل App Engine.
2. الحصول على نموذج تطبيق أساسي
ويتمثّل أحد المتطلّبات الأساسية لهذا الدرس التطبيقي حول الترميز في أن يكون لديك تطبيق نموذجي للوحدة 15 عامل. وإذا لم يكن متوفّرًا لديك، يمكنك الحصول عليه من الوحدة 15 "بدء" (الرابط أدناه). يرشدك هذا الدرس التطبيقي في كل خطوة، إلى الختام باستخدام رمز يشبه ما ورد في الوحدة 16 "FINISH" المجلد.
- بدء: مجلد الوحدة 15 (لغة بايثون 2)
- FINISH: مجلد الوحدة 16 (لغة بايثون 2)
- المستودع بالكامل (لنسخ ملف ZIP أو تنزيله)
يجب أن يبدو دليل ملفات البدء في الوحدة 15 على النحو التالي:
$ ls README.md app.yaml main-gcs.py main.py templates
الملف main-gcs.py
هو إصدار بديل من main.py
من الوحدة 15 يسمح باختيار حزمة Cloud Storage مختلفة عن العنوان التلقائي لعنوان URL المحدَّد للتطبيق استنادًا إلى رقم تعريف المشروع: PROJECT_ID
.appspot.com
. لا يؤدي هذا الملف أي دور في هذا الدرس التطبيقي حول الترميز (الوحدة 16)، أي ما يمكن تطبيق أساليب نقل البيانات المماثلة على هذا الملف إذا لزم الأمر.
3- (إعادة نشر التطبيق الأساسي)
إليك الخطوات المتبقية لتنفيذ العمل المسبق الآن:
- التعرف مرة أخرى على أداة سطر الأوامر
gcloud
- إعادة نشر نموذج التطبيق باستخدام "
gcloud app deploy
" - التأكّد من تشغيل التطبيق على App Engine بدون مشكلة
بعد تنفيذ هذه الخطوات بنجاح والتأكّد من عمل تطبيق الوحدة 15. تستقبل الصفحة الأولى المستخدمين بنموذج يطلب تحميل ملف عناصر الزيارة إلى جانب خيار "تخطّي". زر لإيقاف الميزة:
بعد أن يحمّل المستخدمون ملفًا أو يتخطّونه، يعرض التطبيق "أحدث الزيارات" المألوفة. الصفحة:
سيتم تسجيل "مشاهدة" للزيارات التي تعرض عنصرًا على يسار الطابع الزمني للزيارة لعرض (أو تنزيل) العنصر. بعد تأكيد وظائف التطبيق، ستصبح جاهزًا لنقل البيانات من خدمات App Engine القديمة (webapp2 وNDB وBlobstore) إلى خدمات بديلة معاصرة (Flask وCloud NDB وCloud Storage).
4. تحديث ملفات الإعداد
يتم تشغيل ثلاثة ملفات إعداد للإصدار المحدَّث من التطبيق. المهام المطلوبة هي:
- يجب تعديل مكتبات الجهات الخارجية المُدمَجة المطلوبة في
app.yaml
وإبقاء الباب مفتوحًا لنقل بيانات Python 3. - إضافة
requirements.txt
الذي يحدّد جميع المكتبات المطلوبة غير المضمّنة - إضافة
appengine_config.py
حتى يتوافق التطبيق مع مكتبات الجهات الخارجية المُدمَجة وغير المُدمَجة
app.yaml
يمكنك تعديل ملف app.yaml
من خلال تعديل القسم libraries
. أزِل "jinja2
" وأضِف grpcio
وsetuptools
وssl
. اختر أحدث إصدار متاح للمكتبات الثلاث جميعها. أضِف أيضًا التوجيه runtime
في Python 3، ولكن أدرَجنا تعليقًا. عند الانتهاء، سيبدو على النحو التالي (إذا حددت Python 3.9):
قبل:
runtime: python27
threadsafe: yes
api_version: 1
handlers:
- url: /.*
script: main.app
libraries:
- name: jinja2
version: latest
بعد:
#runtime: python39
runtime: python27
threadsafe: yes
api_version: 1
handlers:
- url: /.*
script: main.app
libraries:
- name: grpcio
version: latest
- name: setuptools
version: latest
- name: ssl
version: latest
تتناول التغييرات بشكل أساسي مكتبات Python 2 المدمجة والمتوفرة على خوادم App Engine (بحيث لا تضطر إلى تجميعها ذاتيًا). أزلنا Jinja2 لأنه يأتي مع Flask، وسنضيفه إلى reqs.txt. عند استخدام مكتبات برامج Google Cloud، مثل مكتبات برامج Cloud NDB وCloud Storage، يجب استخدام grpcio و setuptools. وأخيرًا، تتطلب خدمة Cloud Storage نفسها مكتبة طبقة المقابس الآمنة (SSL). توجيه بيئة التشغيل التي تم التعليق عليها في الأعلى هو عندما تكون مستعدًا لنقل هذا التطبيق إلى Python 3. سنتناول هذا الموضوع في نهاية هذا البرنامج التعليمي.
requirements.txt
أضِف ملف requirements.txt
يتطلّب إطار عمل Flask ومكتبتَي عملاء Cloud NDB وCloud Storage، ولا تتوفّر أي منهما. أنشئ الملف يتضمَّن هذا المحتوى:
flask
google-cloud-ndb
google-cloud-storage
يتطلب وقت تشغيل Python 2 App Engine تجميعًا ذاتيًا لمكتبات تابعة لجهات خارجية غير مضمّنة، لذا نفِّذ الأمر التالي لتثبيت هذه المكتبات في مجلد lib:
pip install -t lib -r requirements.txt
إذا كنت تستخدم Python 2 و3 على جهاز التطوير، فقد تضطر إلى استخدام الأمر pip2 لضمان الحصول على إصدارات Python 2 من هذه المكتبات. بعد الترقية إلى Python 3، لن تحتاج إلى التجميع الذاتي.
appengine_config.py
أضِف ملف appengine_config.py
متوافقًا مع مكتبات الجهات الخارجية المضمَّنة وغير المضمّنة. أنشئ الملف يتضمَّن هذا المحتوى:
import pkg_resources
from google.appengine.ext import vendor
# Set PATH to your libraries folder.
PATH = 'lib'
# Add libraries installed in the PATH folder.
vendor.add(PATH)
# Add libraries to pkg_resources working set to find the distribution.
pkg_resources.working_set.add_entry(PATH)
يجب أن تكون الخطوات المكتملة للتو مماثلة أو مطابقة للخطوات المذكورة في قسم تثبيت المكتبات لتطبيقات Python 2 في مستندات App Engine، وبشكل أكثر تحديدًا، يجب أن يتطابق محتوى appengine_config.py
مع المحتوى الوارد في الخطوة 5 هناك.
اكتمل العمل على ملفات الإعداد، لذا لننتقل إلى التطبيق.
5- تعديل ملفات التطبيق
عمليات الاستيراد
تتضمن المجموعة الأولى من التغييرات في main.py
تبديل جميع العناصر التي يتم استبدالها. في ما يلي بعض التغييرات التي سنُجريها:
- تم استبدال "
webapp2
" بـ "قارورة". - بدلاً من استخدام Jinja2 من
webapp2_extras
، يمكنك استخدام Jinja2 المتوفّر مع Flask. - يتم استبدال App Engine Blobstore وNDB بـ Cloud NDB وCloud Storage.
- يتم استبدال معالِجات Blobstore في
webapp
بمزيج من وحدة المكتبة العاديةio
وأدوات Flask وwerkzeug
. - يكتب Blobstore تلقائيًا في حزمة Cloud Storage تحمل اسم عنوان URL لتطبيقك (
PROJECT_ID.appspot.com
). بما أنّنا ننقل البيانات إلى مكتبة برامج Cloud Storage، يتم استخدامgoogle.auth
للحصول على رقم تعريف المشروع لتحديد اسم الحزمة نفسه بالضبط. (يمكنك تغيير اسم الحزمة بما أنّها لم تعُد تتضمّن ترميزًا ثابتًا).
قبل:
import webapp2
from webapp2_extras import jinja2
from google.appengine.ext import blobstore, ndb
from google.appengine.ext.webapp import blobstore_handlers
نفِّذ التغييرات في القائمة أعلاه عن طريق استبدال قسم الاستيراد الحالي في main.py
بمقتطف الرمز أدناه.
بعد:
import io
from flask import (Flask, abort, redirect, render_template,
request, send_file, url_for)
from werkzeug.utils import secure_filename
import google.auth
from google.cloud import exceptions, ndb, storage
الإعداد ودعم Jinja2 غير الضروري
مجموعة الرموز التالية التي يجب استبدالها هي BaseHandler
التي تحدّد استخدام Jinja2 من webapp2_extras
. هذا غير ضروري لأن Jinja2 يأتي مع Flask وهو محرك النماذج الافتراضي، لذا قم بإزالته.
على جانب الوحدة 16، يتم إنشاء مثيل لكائنات لم تكن متوفرة في التطبيق القديم. يشمل ذلك إعداد تطبيق Flask وإنشاء برامج واجهة برمجة تطبيقات لكلّ من Cloud NDB وCloud Storage. أخيرًا، وضعنا اسم حزمة Cloud Storage معًا كما هو موضّح أعلاه في قسم الاستيراد. وفي ما يلي الفترة السابقة لتنفيذ هذه التحديثات وبعدها:
قبل:
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))
بعد:
app = Flask(__name__)
ds_client = ndb.Client()
gcs_client = storage.Client()
_, PROJECT_ID = google.auth.default()
BUCKET = '%s.appspot.com' % PROJECT_ID
تعديل إذن الوصول إلى مخزن البيانات
Cloud NDB متوافق في الغالب مع App Engine NDB. وهناك اختلاف واحد تم تناوله مسبقًا هو الحاجة إلى عميل واجهة برمجة التطبيقات. والقيد الآخر هو أن يتم التحكم في الوصول إلى مخزن البيانات عن طريق مدير سياق بايثون لعميل واجهة برمجة التطبيقات. وهذا يعني في الأساس أن جميع طلبات الوصول إلى Datastore التي تستخدم مكتبة برامج Cloud NDB لا يمكن أن تحدث إلا ضمن مجموعات Python with
.
هذا تغيير واحد؛ والأخرى هي أن Blobstore وكائناتها، مثل لا تتوافق أسماء BlobKey
مع Cloud Storage، لذا غيِّر file_blob
إلى ndb.StringProperty
بدلاً من ذلك. في ما يلي فئة نموذج البيانات والدالتان store_visit()
وfetch_visits()
المعدَّلتان اللتان تعكسان هذه التغييرات:
قبل:
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)
بعد:
class Visit(ndb.Model):
'Visit entity registers visitor IP address & timestamp'
visitor = ndb.StringProperty()
timestamp = ndb.DateTimeProperty(auto_now_add=True)
file_blob = ndb.StringProperty()
def store_visit(remote_addr, user_agent, upload_key):
'create new Visit entity in Datastore'
with ds_client.context():
Visit(visitor='{}: {}'.format(remote_addr, user_agent),
file_blob=upload_key).put()
def fetch_visits(limit):
'get most recent visits'
with ds_client.context():
return Visit.query().order(-Visit.timestamp).fetch(limit)
في ما يلي تمثيل مصوّر للتغييرات التي تمّ إجراؤها حتى الآن:
تحديث المعالجات
معالِج التحميل
المعالِجات في "webapp2
" هي صفوف أثناء وظيفتها في تطبيق Flask. بدلاً من طريقة فعل HTTP، تستخدم Flask الفعل لتزيين الدالة. يتم استبدال Blobstore ومعالجات webapp
بوظائف من Cloud Storage بالإضافة إلى Flask وأدواته:
قبل:
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)
بعد:
@app.route('/upload', methods=['POST'])
def upload():
'Upload blob (POST) handler'
fname = None
upload = request.files.get('file', None)
if upload:
fname = secure_filename(upload.filename)
blob = gcs_client.bucket(BUCKET).blob(fname)
blob.upload_from_file(upload, content_type=upload.content_type)
store_visit(request.remote_addr, request.user_agent, fname)
return redirect(url_for('root'), code=307)
في ما يلي بعض الملاحظات حول هذا التعديل:
- بدلاً من
blob_id
، يتم الآن تحديد عناصر الملف باستخدام اسم الملف (fname
) في حال توفّره وNone
(في حال أوقف المستخدم تحميل ملف). - استبعدت معالجات Blobstore عملية التحميل من المستخدمين، على عكس Cloud Storage. لذا يمكنك الاطّلاع على الرمز المُضاف حديثًا الذي يضبط كائن الكائن الثنائي الكبير (blob) وموقعه (الحزمة) بالإضافة إلى الاستدعاء الذي ينفّذ التحميل الفعلي. (
upload_from_file()
). - يستخدم
webapp2
جدول توجيه أسفل ملف التطبيق، بينما يمكن العثور على مسارات Flask في كل معالج مزخرف. - ويلخّص كلا المعالجَين وظائفهما من خلال إعادة التوجيه إلى الصفحة الرئيسية (
/
) مع الحفاظ على طلبPOST
باستخدام رمز الرجوع HTTP 307.
معالِج التنزيل
يتبع تحديث معالج التنزيل نمطًا مشابهًا لمعالج التحميل، ولكن ما مِن رموز يجب معالجتها. استبدِل وظيفتَي Blobstore وwebapp
بالعناصر المكافئة لها في Cloud Storage وFlood:
قبل:
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)
بعد:
@app.route('/view/<path:fname>')
def view(fname):
'view uploaded blob (GET) handler'
blob = gcs_client.bucket(BUCKET).blob(fname)
try:
media = blob.download_as_bytes()
except exceptions.NotFound:
abort(404)
return send_file(io.BytesIO(media), mimetype=blob.content_type)
ملاحظات حول هذا التعديل:
- مرة أخرى، تُزيِّن Flask وظائف المعالِج بمساره، بينما ينفذ
webapp
ذلك في جدول توجيه في الأسفل، لذا يجب التعرّف على بنية مطابقة النمط('/view/([^/]+)?'
لـ Flask ('/view/<path:fname>'
). - كما هو الحال مع معالج التحميل، هناك بعض الإجراءات المطلوبة من جانب Cloud Storage للحصول على الوظائف التي تتم إزالتها من خلال معالِجات Blobstore، وتحديدًا تحديد الملف (blob) المعني وتنزيل طلب الطريقة
send_blob()
واحد لمعالج Blobstore بشكل صريح. - وفي كلتا الحالتين، يتم عرض خطأ HTTP 404 للمستخدم إذا لم يتم العثور على أي عنصر.
المعالج الرئيسي
تحدث التغييرات النهائية على التطبيق الرئيسي في المعالج الرئيسي. يتم استبدال طرق فعل HTTP webapp2
بدالة واحدة تجمع وظائفها. استبدِل الفئة MainHandler
بالدالة root()
وأزِل جدول التوجيه webapp2
كما هو موضّح أدناه:
قبل:
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)
بعد:
@app.route('/', methods=['GET', 'POST'])
def root():
'main application (GET/POST) handler'
context = {}
if request.method == 'GET':
context['upload_url'] = url_for('upload')
else:
context['visits'] = fetch_visits(10)
return render_template('index.html', **context)
بدلاً من الفصل بين طريقتَي get()
وpost()
، تمثّل هذه الطريقة في الأساس عبارة if-else
في root()
. بالإضافة إلى ذلك، بما أنّ root()
هي دالة واحدة، فإنّه يتم عرض النموذج لكل من GET
وPOST
باستخدام استدعاء واحد فقط، بينما لا يمكن تنفيذ ذلك في webapp2
.
في ما يلي عرض مصوّر للمجموعة الثانية والأخيرة من التغييرات التي تم إجراؤها على "main.py
":
(اختياري) "تحسين" التوافق مع الأنظمة القديمة
لذا فإن الحل الذي تم إنشاؤه أعلاه يعمل بشكل مثالي... ولكن فقط إذا كنت تبدأ من نقطة الصفر ولا تكون لديك ملفات تم إنشاؤها بواسطة Blobstore. نظرًا لأنّنا عدّلنا التطبيق لتحديد الملفات حسب اسم الملف بدلاً من BlobKey
، لن يتمكّن تطبيق الوحدة 16 المكتمل كما هو من عرض ملفات Blobstore. بمعنى آخر، لقد أجرينا تغييرًا غير متوافق مع الإصدارات القديمة أثناء عملية نقل البيانات هذه. ونقدّم الآن نسخة بديلة من main.py
باسم main-migrate.py
(متوفّرة في المستودع) تحاول سد هذه الفجوة.
"الإضافة" الأولى لإتاحة الملفات التي تم إنشاؤها على Blobstore، يتوفّر نموذج بيانات يحتوي على BlobKeyProperty
(بالإضافة إلى StringProperty
للملفات التي تم إنشاؤها في Cloud Storage):
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() # backwards-compatibility
file_gcs = ndb.StringProperty()
سيتم استخدام السمة file_blob
لتحديد الملفات التي تم إنشاؤها من خلال Blobstore، بينما يتم استخدام السمة file_gcs
لملفات Cloud Storage. الآن عند إنشاء زيارات جديدة، خزِّن قيمة بشكلٍ صريح في file_gcs
بدلاً من file_blob
، بحيث تبدو store_visit تبدو مختلفة قليلاً:
قبل:
def store_visit(remote_addr, user_agent, upload_key):
'create new Visit entity in Datastore'
with ds_client.context():
Visit(visitor='{}: {}'.format(remote_addr, user_agent),
file_blob=upload_key).put()
بعد:
def store_visit(remote_addr, user_agent, upload_key):
'create new Visit entity in Datastore'
with ds_client.context():
Visit(visitor='{}: {}'.format(remote_addr, user_agent),
file_gcs=upload_key).put()
عند جلب أحدث الزيارات، يجب "تسوية" البيانات قبل إرسالها إلى القالب:
قبل:
@app.route('/', methods=['GET', 'POST'])
def root():
'main application (GET/POST) handler'
context = {}
if request.method == 'GET':
context['upload_url'] = url_for('upload')
else:
context['visits'] = fetch_visits(10)
return render_template('index.html', **context)
بعد:
@app.route('/', methods=['GET', 'POST'])
def root():
'main application (GET/POST) handler'
context = {}
if request.method == 'GET':
context['upload_url'] = url_for('upload')
else:
context['visits'] = etl_visits(fetch_visits(10))
return render_template('index.html', **context)
بعد ذلك، يجب تأكيد توفُّر file_blob
أو file_gcs
(أو عدم توفّر أي منهما). في حال توفّر ملف، اختَر الملف المتوفّر واستخدِم هذا المعرّف (BlobKey
للملفات التي تم إنشاؤها في Blobstore أو اسم الملف للملفات التي تم إنشاؤها في Cloud Storage). عندما نقول "الملفات التي تم إنشاؤها في Cloud Storage"، ونقصد بذلك الملفات التي تم إنشاؤها باستخدام مكتبة برامج Cloud Storage. يكتب Blobstore أيضًا بيانات في Cloud Storage أيضًا، ولكن في هذه الحالة، ستكون هذه الملفات من إنشاء Blobstore.
والأهم من ذلك، ما هي دالة etl_visits()
هذه المستخدمة لاستخراج البيانات وتحويلها وتحميلها (ETL) للمستخدم النهائي؟ تبدو هكذا:
def etl_visits(visits):
return [{
'visitor': v.visitor,
'timestamp': v.timestamp,
'file_blob': v.file_gcs if hasattr(v, 'file_gcs') \
and v.file_gcs else v.file_blob
} for v in visits]
قد يبدو الأمر كما توقعت: يتم تكرار الرمز عبر جميع الزيارات، ولكل زيارة، يأخذ بيانات الزائر والطابع الزمني حرفيًا، ثم يتحقّق من وجود file_gcs
أو file_blob
، وإذا كان الأمر كذلك، يتم اختيار إحداهما (أو None
في حال عدم توفّرها).
في ما يلي توضيح للاختلافات بين main.py
وmain-migrate.py
:
إذا كنت تبدأ من الصفر بدون استخدام الملفات التي أنشأها Blobstore، استخدِم main.py
، وإذا أردت استخدام ملفات متوافقة تم إنشاؤها من خلال كل من Blobstore و Cloud Storage، يمكنك الاطّلاع على main-migrate.py
كمثال على كيفية التعامل مع سيناريو لمساعدتك في التخطيط لعمليات نقل البيانات لتطبيقاتك الخاصة. عند إجراء عمليات نقل بيانات معقدة، من المحتمل أن تظهر حالات خاصة، لذا يهدف هذا المثال إلى إظهار اهتمام أكبر بتحديث التطبيقات الحقيقية باستخدام بيانات حقيقية.
6- الملخّص/تنظيف البيانات
يلخّص هذا القسم هذا الدرس التطبيقي حول الترميز من خلال نشر التطبيق، والتأكّد من أنّه يعمل على النحو المطلوب وفي أي نتائج أخرى. بعد التحقّق من صحة التطبيق، نفِّذ أي خطوات تنظيف وفكِّر في الخطوات التالية.
نشر التطبيق والتحقق منه
قبل إعادة نشر تطبيقك، احرص على تشغيل pip install -t lib -r requirements.txt
للحصول على مكتبات الجهات الخارجية المجمَّعة ذاتيًا في مجلد lib. إذا أردت تشغيل الحل المتوافق مع الإصدارات القديمة، عليك إعادة تسمية main-migrate.py
باسم main.py
أولاً. شغِّل الآن gcloud app deploy
، وتأكَّد من أنّ التطبيق يعمل بشكل متطابق مع تطبيق الوحدة 15. تظهر شاشة النموذج على النحو التالي:
تظهر صفحة الزيارات الأخيرة على النحو التالي:
تهانينا على إكمال هذا الدرس التطبيقي حول الترميز، بدلاً من App Engine Blobstore مع Cloud Storage، وApp Engine NDB مع Cloud NDB، وwebapp2
مع Flask. يجب أن يكون الرمز متطابقًا الآن مع مجلد FINISH (Module 16). يتوفّر main-migrate.py
البديل أيضًا في هذا المجلد.
"نقل البيانات" في لغة Python 3
كل ما تحتاج إليه هو توجيه Python 3 runtime
الذي تم التعليق عليه في أعلى app.yaml
لنقل هذا التطبيق إلى Python 3. فرمز المصدر نفسه متوافق مع Python 3، وبالتالي لا يلزم إجراء أي تغييرات. لنشر هذا التطبيق كتطبيق Python 3، يجب تنفيذ الخطوات التالية:
- ألغِ تعليق التوجيه
runtime
في Python 3 أعلىapp.yaml
. - احذف جميع الأسطر الأخرى في
app.yaml
. - احذف الملف
appengine_config.py
. (غير مستخدم في وقت تشغيل Python 3) - احذف المجلد "
lib
" إذا كان متوفّرًا. (غير ضروري مع وقت تشغيل Python 3)
تَنظيم
بنود عامة
إذا كنت قد انتهيت الآن، ننصحك بإيقاف تطبيق 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
". إذا كان التطبيق مستضافًا في الولايات المتحدة الأمريكية
من ناحية أخرى، إذا كنت لا تريد مواصلة استخدام هذا التطبيق أو الدروس التطبيقية الأخرى ذات الصلة لنقل البيانات وأردت حذف جميع البيانات بالكامل، عليك إيقاف مشروعك.
خصوصيّة هذا الدرس التطبيقي حول الترميز
الخدمات المدرَجة أدناه هي خدمات فريدة لهذا الدرس التطبيقي حول الترميز. ارجع إلى وثائق كل منتج لمزيد من المعلومات:
- تندرج خدمة App Engine Blobstore ضمن حصص وحدود البيانات المُخزَّنة، لذا يُرجى مراجعتها بالإضافة إلى صفحة أسعار الخدمات المجمّعة القديمة.
- توفّر خدمة Cloud Storage فئة مجانية لمناطق محدّدة. يمكنك أيضًا الاطّلاع على صفحة الأسعار العامة للحصول على مزيد من المعلومات.
- يتم تقديم خدمة مخزن بيانات App Engine من خلال Cloud Datastore (Cloud Firestore في وضع "مخزن البيانات") التي توفّر أيضًا فئة مجانية. يمكنك الاطّلاع على صفحة الأسعار للحصول على مزيد من المعلومات".
تجدر الإشارة إلى أنّه في حال النقل من الوحدة 15 إلى 16، ستظلّ لديك بيانات في Blobstore، ولهذا السبب سنُضمِّن معلومات الأسعار أعلاه.
الخطوات التالية
بالإضافة إلى هذا البرنامج التعليمي، تشمل وحدات نقل البيانات الأخرى التي تركز على الانتقال من الخدمات المجمّعة القديمة التي يجب مراعاتها ما يلي:
- الوحدة 2: النقل من App Engine
ndb
إلى Cloud NDB - الوحدات 7-9: نقل المهام من قائمة انتظار مهام App Engine إلى "مهام السحابة الإلكترونية"
- الوحدات 12-13: النقل من App Engine Memcache إلى Cloud Memorystore
- الوحدات 18-19: النقل من قائمة انتظار مهام App Engine (سحب المهام) إلى Cloud Pub/Sub
لم يعد App Engine النظام الأساسي الوحيد بدون خوادم في Google Cloud. إذا كان لديك تطبيق App Engine صغير أو تطبيق ذو وظائف محدودة وتريد تحويله إلى خدمة مصغّرة مستقلة، أو إذا كنت تريد تقسيم تطبيق متجانس إلى عدة مكوّنات قابلة لإعادة الاستخدام، هذه هي الأسباب الوجيهة للانتقال إلى وظائف السحابة الإلكترونية. إذا أصبحت عملية التطوير جزءًا من سير عمل تطوير التطبيقات، خاصةً إذا كانت تتألف من مسار CI/CD (التكامل المستمر أو العرض أو النشر المستمر)، ننصحك بنقل البيانات إلى تشغيل السحابة الإلكترونية. تغطي الوحدات التالية هذه السيناريوهات:
- نقل البيانات من App Engine إلى Cloud Functions: راجِع الوحدة 11.
- نقل البيانات من App Engine إلى Cloud Run: راجِع الوحدة 4 لتضمين تطبيقك مع Docker، أو الوحدة 5 لتنفيذ ذلك بدون حاويات أو معلومات Docker أو
Dockerfile
s.
إنّ التبديل إلى نظام أساسي آخر بدون خادم هو إجراء اختياري، وننصحك بالتفكير في أفضل الخيارات لتطبيقاتك وحالات الاستخدام قبل إجراء أي تغييرات.
بغض النظر عن وحدة نقل البيانات التي تفكر فيها بعد ذلك، يمكن الوصول إلى كل محتوى محطة النقل بدون خادم (الدروس التطبيقية حول الترميز والفيديوهات ورمز المصدر [عند توفّره]) من خلال مستودع البرامج المفتوحة المصدر. يوفّر README
الخاص بالمستودع أيضًا إرشادات حول عمليات نقل البيانات التي يجب أخذها في الاعتبار وأي "طلب" ذي صلة. لوحدات النقل.
7. مراجع إضافية
المشاكل/الملاحظات في الدرس التطبيقي حول الترميز
إذا وجدت أي مشاكل في هذا الدرس التطبيقي حول الترميز، يُرجى البحث عن مشكلتك أولاً قبل ملء النموذج. روابط للبحث وإنشاء مشاكل جديدة:
موارد نقل البيانات
يمكن العثور على روابط لمجلدات repo للوحدة 15 (بدء) والوحدة 16 (FINISH) في الجدول أدناه. يمكن أيضًا الوصول إليها من المستودع الخاص بجميع عمليات نقل البيانات التطبيقية حول الترميز في App Engine، والتي يمكنك استنساخ ملف ZIP أو تنزيله.
Codelab | Python 2 | Python 3 |
الوحدة 15 | لا ينطبق | |
الوحدة 16 (هذا الدرس التطبيقي حول الترميز) | (مثل Python 2) |
مراجع على الإنترنت
في ما يلي موارد على الإنترنت قد تكون ذات صلة بهذا البرنامج التعليمي:
التخزين في السحابة الإلكترونية وApp Engine Blobstore
- خدمة App Engine Blobstore
- نقل البيانات إلى مكتبة برامج Cloud Storage
- صفحة Cloud Storage الرئيسية
- مستندات Cloud Storage
منصة App Engine
- مستندات App Engine
- وقت تشغيل Python 2 App Engine (بيئة عادية)
- استخدام المكتبات المضمَّنة في App Engine على Python 2 App Engine
- وقت تشغيل Python 3 App Engine (بيئة عادية)
- الاختلافات بين Python 2 3 بيئات تشغيل App Engine (بيئة عادية)
- دليل نقل البيانات من الإصدار 2 إلى 3 من App Engine (البيئة العادية)
- معلومات حول الأسعار والحصص في App Engine
- إطلاق الجيل الثاني من منصة App Engine (2018)
- المقارنة بين الدرجة الأولى و منصات من الجيل الثاني
- إتاحة بيئات التشغيل القديمة على المدى الطويل
- مستودع نماذج نقل بيانات المستندات
- مستودع نماذج نقل البيانات التي يساهم بها المجتمع
معلومات أخرى عن السحابة الإلكترونية
- Python على Google Cloud Platform
- مكتبات برامج Google Cloud Python
- "المجانية دائمًا" في Google Cloud الفئة
- Google Cloud SDK (أداة سطر أوامر
gcloud
) - جميع مستندات Google Cloud
Python
- أنظمة إنشاء النماذج Django وJinja2
- إطار عمل الويب
webapp2
- مستندات
webapp2
- روابط
webapp2_extras
- مستندات
webapp2_extras
Jinja2 - إطار عمل الويب من Flask
الفيديوهات
- محطة نقل بدون خادم
- الاستكشافات بدون خادم
- الاشتراك في Google Cloud Tech
- الاشتراك في Google Developers
الترخيص
هذا العمل مرخّص بموجب رخصة المشاع الإبداعي 2.0 مع نسب العمل إلى مؤلف عام.