نحوه استفاده از App Engine blobstore (واحد ۱۵)

۱. نمای کلی

هدف از مجموعه codelabهای Serverless Migration Station (آموزش‌های عملی با سرعت پیشروی دلخواه) و ویدیوهای مرتبط کمک به توسعه‌دهندگان Google Cloud serverless برای مدرن‌سازی برنامه‌هایشان ازطریق راهنمایی آن‌ها در یک یا چند انتقال، عمدتاً با فاصله گرفتن از سرویس‌های قدیمی، است. این کار باعث می‌شود برنامه‌هایتان قابل‌حمل‌تر شوند و گزینه‌ها و انعطاف‌پذیری بیشتری به شما می‌دهد، و به شما امکان می‌دهد با طیف وسیع‌تری از محصولات Cloud ادغام شوید و به آن‌ها دسترسی داشته باشید و راحت‌تر به نسخه‌های جدیدتر زبان ارتقا دهید. درحالی‌که این مجموعه در ابتدا بر اولین کاربران Cloud، عمدتاً توسعه‌دهندگان App Engine (محیط استاندارد)، تمرکز دارد، به‌اندازه کافی گسترده است که شامل پلاتفرم‌های بدون سرور دیگر مانند Cloud Functions و Cloud Run، یا جاهای دیگر درصورت لزوم، شود.

این codelab واحد ۱۵ توضیح می‌دهد که چگونه استفاده از App Engineblobstore را به برنامه نمونه از واحد ۰ اضافه کنید. سپس آماده خواهید بود تا در واحد ۱۶ آن استفاده را به «فضای ذخیره‌سازی ابری» انتقال دهید.

با روش انجام این کارها آشنا خواهید شد

  • افزودن استفاده از کتابخانه/ میانای برنامه‌سازی کاربردی App Engine Blobstore
  • ذخیره کردن بارگذاری‌های کاربر در سرویس blobstore
  • برای مرحله بعدی انتقال به Cloud Storage آماده شوید

آنچه نیاز خواهید داشت

نظرسنجی

چگونه از این آموزش استفاده خواهید کرد؟

فقط آن را بخوانید آن را بخوانید و تمرین‌ها را تکمیل کنید

تجربه‌تان را با Python چگونه رده‌بندی می‌کنید؟

مبتدی متوسط ماهر

به تجربه استفاده از سرویس‌های Google Cloud چه امتیازی می‌دهید؟

مبتدی متوسط ماهر

۲. پس‌زمینه

برای انتقال از App Engine Blobstore API، استفاده از آن را به برنامه App Engine ndb پایه موجود از واحد ۰ اضافه کنید. برنامه نمونه ده بازدید اخیر را به کاربر نشان می‌دهد. درحال اصلاح برنامه هستیم تا از کاربر نهایی بخواهد مصنوع (فایل) مربوط به «بازدید» خود را بارگذاری کند. اگر کاربر مایل به انجام این کار نباشد، گزینه «رد شدن» وجود دارد. صرف‌نظر از تصمیم کاربر، صفحه بعدی همان خروجی برنامه را از «واحد ۰» (و بسیاری از واحدهای دیگر در این مجموعه) ارائه می‌دهد. با پیاده‌سازی این ادغام App Engine blobstore، می‌توانیم آن را در codelab بعدی (واحد ۱۶) به فضای ذخیره‌سازی ابری منتقل کنیم.

‫App Engine دسترسی به سیستم‌های قالب‌بندی Django و Jinja2 را فراهم می‌کند، و چیزی که این مثال را متفاوت می‌کند (علاوه‌بر افزودن دسترسی Blobstore) این است که از Django در واحد ۰ به Jinja2 در واحد ۱۵ تغییر می‌کند. یکی از مراحل کلیدی در نوسازی برنامه‌های App Engine، انتقال چارچوب‌های وب از webapp2 به Flask است. مورد دوم از Jinja2 به‌عنوان سیستم الگوسازی پیش‌فرض خود استفاده می‌کند، بنابراین ما با پیاده‌سازی Jinja2 درحالی‌که برای دسترسی به Blobstore در webapp2 می‌مانیم، شروع به حرکت در آن جهت می‌کنیم. ازآنجایی‌که Flask به‌طور پیش‌فرض از Jinja2 استفاده می‌کند، این یعنی در «واحد ۱۶» نیازی به تغییر الگو نخواهد بود.

۳. راه‌اندازی/ پیش‌کار

قبل‌از اینکه به بخش اصلی آموزش برسیم، پروژه‌تان را راه‌اندازی کنید، کد را دریافت کنید، و برنامه پایه را مستقر کنید تا با کد فعال شروع کنید.

۱. راه‌اندازی پروژه

اگر قبلاً برنامه «واحد ۰» را مستقر کرده‌اید، توصیه می‌کنیم از همان پروژه (و کد) دوباره استفاده کنید. به‌علاوه، می‌توانید پروژه کاملاً جدیدی ایجاد کنید یا از پروژه موجود دیگری دوباره استفاده کنید. مطمئن شوید پروژه حساب صورت‌حساب فعال داشته باشد و App Engine فعال باشد.

۲. دریافت برنامه نمونه پایه

یکی از پیش‌نیازهای این codelab داشتن یک برنامه نمونه Module 0 فعال است. اگر آن را ندارید، می‌توانید آن را از پوشه «START» Module 0 (پیوند زیر) دریافت کنید. این codelab شما را در هر مرحله راهنمایی می‌کند و با کدی شبیه به آنچه در پوشه «FINISH» (پایان) واحد ۱۵ وجود دارد به پایان می‌رسد.

فهرست راهنمای فایل‌های STARTing «واحد ۰» باید به این شکل باشد:

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

۳. استقرار (مجدد) برنامه مبنا

مراحل پیش‌کار باقی‌مانده شما برای اجرا درحال‌حاضر:

  1. دوباره با ابزار خط فرمان gcloud آشنا شوید
  2. برنامه نمونه را با gcloud app deploy دوباره مستقر کنید
  3. تأیید کنید که برنامه بدون مشکل در App Engine اجرا می‌شود

وقتی این مراحل را با موفقیت اجرا کردید و دیدید که برنامه وب شما کار می‌کند (با خروجی مشابه زیر)، آماده‌اید که استفاده از ذخیره‌سازی در حافظه نهان را به برنامه‌تان اضافه کنید.

a7a9d2b80d706a2b.png

۴. به‌روزرسانی فایل‌های پیکربندی

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

هیچ فایل پیکربندی دیگری نیاز به به‌روزرسانی ندارد، بنابراین بیایید به فایل‌های برنامه برویم.

۵. اصلاح فایل‌های برنامه

وارد کردن و پشتیبانی Jinja2

اولین مجموعه تغییرات برای main.py شامل افزودن استفاده از Blobstore API و جایگزینی قالب‌بندی 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 جدیدی برای دریافت تغییرمسیر ۳۰۷ شرح‌داده‌شده در بالا نیاز دارد.

قبل‌از این به‌روزرسانی‌ها، برنامه «واحد ۰» فقط یک گرداننده اصلی با روش 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)

با اعمال این به‌روزرسانی‌ها، اکنون سه گرداننده وجود دارد: ۱) گرداننده بارگذاری با روش POST، ۲) گرداننده بارگیری «مشاهده حباب» با روش GET، و ۳) گرداننده اصلی با روش‌های 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 وجود دارد. این فراخوانی نشانی وبی را تولید می‌کند که فرم به آن POST می‌کند، و با فراخوانی گرداننده بارگذاری، فایل را به Blobstore ارسال می‌کند.
  • در UploadHandler.post، تماسی با blobstore_handlers.BlobstoreUploadHandler.get_uploads وجود دارد. این جادوی واقعی است که فایل را در Blobstore قرار می‌دهد و یک شناسه منحصربه‌فرد و دائمی برای آن فایل، یعنی BlobKey، برمی‌گرداند.
  • در ViewBlobHandler.get، فراخوانی blobstore_handlers.BlobstoreDownloadHandler.send با BlobKey فایل منجر به واکشی فایل و بازارسال آن به مرورگر کاربر نهایی می‌شود

این فراخوانی‌ها نشان‌دهنده بخش عمده دسترسی به ویژگی‌های اضافه‌شده به برنامه است. در اینجا تصویری از این مجموعه دوم و نهایی تغییرات در main.py ارائه شده است:

da2960525ac1b90d.png

به‌روزرسانی الگوی HTML

برخی‌از به‌روزرسانی‌های برنامه اصلی بر میانای کاربر (UI) برنامه تأثیر می‌گذارد، بنابراین تغییرات مربوطه در الگوی وب لازم است، درواقع دو تغییر:

  1. فرم بارگذاری فایل با ۳ عنصر ورودی لازم است: یک فایل و یک جفت دکمه ارسال برای بارگذاری فایل و رد شدن، به‌ترتیب.
  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 به برنامه نمونه «واحد ۰» را انجام داده‌اید.

(اختیاری) «بهبود» فضای ذخیره‌سازی ابری

فضای ذخیره‌سازی Blobstore درنهایت به خود «فضای ذخیره‌سازی ابری» تبدیل شد. این یعنی بارگذاری‌های Blobstore در کنسول Cloud، به‌ویژه مرورگر 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 Standard Library برای تأیید نوع تصویر اعتبارسنجی خواهید کرد. درنهایت، احتمالاً می‌خواهید اندازه بارگذاری‌ها را محدود کنید تا از سوءاستفاده جلوگیری شود.

فرض کنیم همه این کارها انجام شده است. چگونه می‌توانیم برنامه‌مان را به‌روز کنیم تا از تعیین محل ذخیره فایل‌های بارگذاری‌شده پشتیبانی کند؟ نکته کلیدی این است که فراخوانی 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

‫۶. خلاصه/پاک‌سازی

این بخش با استقرار برنامه، درستی‌سنجی عملکرد موردانتظار آن، و هر برونداد منعکس‌شده‌ای، این codelab را به پایان می‌رساند. پس‌از اعتبارسنجی برنامه، مراحل پاک‌سازی را انجام دهید و مراحل بعدی را درنظر بگیرید.

استقرار و درستی‌سنجی برنامه

برنامه‌تان را با gcloud app deploy دوباره مستقر کنید و تأیید کنید که برنامه همان‌طور که تبلیغ شده است کار می‌کند و ازنظر تجربه کاربری (UX) با برنامه «واحد ۰» متفاوت است. اکنون دو صفحه متفاوت در برنامه‌تان وجود دارد، صفحه اول پیام‌واره فرم بارگذاری فایل بازدید است:

f5b5f9f19d8ae978.pngاز آنجا، کاربران نهایی یا فایلی را بارگذاری می‌کنند و روی «ارسال» کلیک می‌کنند یا روی «رد شدن» کلیک می‌کنند تا چیزی بارگذاری نشود. در هر دو مورد، نتیجه جدیدترین صفحه بازدید است که اکنون با پیوندهای «مشاهده» یا «هیچ‌کدام» بین مُهرهای زمان بازدید و اطلاعات بازدیدکننده تقویت شده است:

f5ac6b98ee8a34cb.png

تبریک می‌گوییم که این codelab را برای افزودن استفاده از App Engine Blobstore به برنامه نمونه «واحد ۰» تکمیل کردید. کد شما اکنون باید با آنچه در پوشه FINISH (واحد ۱۵) است مطابقت داشته باشد. main-gcs.py جایگزین نیز در آن پوشه وجود دارد.

مرتب‌سازی

عمومی

اگر کارتان تمام شده است، توصیه می‌کنیم برنامه App Engine خود را غیرفعال کنید تا از ایجاد صورت‌حساب جلوگیری شود. بااین‌حال، اگر می‌خواهید بیشتر آزمایش یا تجربه کنید، پلاتفرم App Engine دارای سهمیه رایگان است و تا زمانی که از آن سطح استفاده فراتر نروید، هزینه‌ای از شما کسر نخواهد شد. این هزینه برای محاسبه است، اما ممکن است برای سرویس‌های App Engine مربوطه نیز هزینه‌هایی وجود داشته باشد، بنابراین برای اطلاعات بیشتر صفحه قیمت‌گذاری آن را بررسی کنید. اگر این انتقال شامل سرویس‌های Cloud دیگر باشد، صورت‌حساب آن‌ها به‌طور جداگانه صادر می‌شود. در هر دو مورد، درصورت وجود، بخش «مختص این codelab» را در زیر ببینید.

برای شفاف‌سازی کامل، استقرار در پلتفرم محاسباتی بدون‌سرور 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*ation شما بستگی دارد، برای مثال، اگر برنامه‌تان در ایالات متحده میزبانی می‌شود، «us».

ازسوی دیگر، اگر نمی‌خواهید این برنامه یا سایر codelabهای انتقال مرتبط را ادامه دهید و می‌خواهید همه چیز را به‌طور کامل حذف کنید، پروژه‌تان را خاموش کنید.

مختص این codelab

سرویس‌های فهرست‌شده در زیر مختص این codelab است. برای کسب اطلاعات بیشتر، به اسناد هر محصول مراجعه کنید:

مراحل بعدی

انتقال منطقی بعدی که باید درنظر گرفته شود در واحد ۱۶ پوشش داده شده است، که به توسعه‌دهندگان نشان می‌دهد چگونه از سرویس App Engine Blobstore به استفاده از کتابخانه کلاینت «فضای ذخیره‌سازی ابری» انتقال دهند. مزایای ارتقا شامل دسترسی به ویژگی‌های بیشتر Cloud Storage، آشنایی با کتابخانه کارخواهی که برای برنامه‌های خارج از App Engine کار می‌کند، چه در Google Cloud، چه در ابرهای دیگر، یا حتی در محل. اگر احساس می‌کنید به همه ویژگی‌های موجود در «فضای ذخیره‌سازی ابری» نیاز ندارید یا نگران تأثیر آن بر هزینه هستید، می‌توانید در App Engine Blobstore بمانید.

فراتر از واحد ۱۶، تعداد زیادی انتقال‌های احتمالی دیگر مانند Cloud NDB و Cloud Datastore،‏ Cloud Tasks، یا Cloud Memorystore وجود دارد. همچنین انتقال‌های بین‌محصولی به Cloud Run و Cloud Functions وجود دارد. مخزن انتقال همه نمونه‌های کد را ارائه می‌دهد، شما را به همه آزمایشگاه‌های کد و ویدیوهای موجود پیوند می‌دهد، و همچنین راهنمایی‌هایی درباره اینکه کدام انتقال‌ها را درنظر بگیرید و هرگونه «ترتیب» مربوط به انتقال‌ها ارائه می‌دهد.

‫۷. منابع بیشتر

مشکلات/ بازخورد Codelab

اگر مشکلی در این codelab پیدا کردید، لطفاً قبل‌از ثبت آن، ابتدا مشکلتان را جستجو کنید. پیوندهای جستجو و ایجاد مشکلات جدید:

منابع انتقال

پیوندهای پوشه‌های مخزن برای «واحد ۰» (شروع) و «واحد ۱۵» (پایان) را می‌توانید در جدول زیر پیدا کنید. همچنین می‌توانید ازطریق مخزن همه انتقال‌های کارگاه کد App Engine به آن‌ها دسترسی پیدا کنید و فایل ZIP را شبیه‌سازی یا بارگیری کنید.

Codelab

Python 2

Python 3

واحد ۰

کد

نامشخص

واحد ۱۵ (این codelab)

کد

نامشخص

منابع آنلاین

در زیر منابع آنلاینی آمده است که ممکن است برای این آموزش مفید باشد:

App Engine

Google Cloud

Python

ویدیوها

گواهینامه رانندگی

این اثر تحت «پروانه مشترکات خلاقانه با ذکر مؤلف نسخه ۲.۰» است.