نحوه استفاده از App Engine blobstore (ماژول 15)

۱. مرور کلی

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

این آزمایشگاه کد ماژول ۱۵ توضیح می‌دهد که چگونه می‌توان استفاده blobstore اپ انجین را به برنامه نمونه از ماژول ۰ اضافه کرد. سپس شما آماده خواهید بود تا آن استفاده را در ماژول ۱۶ به فضای ذخیره‌سازی ابری منتقل کنید .

یاد خواهید گرفت که چگونه

  • استفاده از API/کتابخانه‌ی App Engine Blobstore را اضافه کنید
  • ذخیره آپلودهای کاربر در سرویس blobstore
  • برای مرحله بعدی مهاجرت به فضای ذخیره‌سازی ابری آماده شوید

آنچه نیاز دارید

نظرسنجی

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

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

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

تازه کار متوسط ماهر

تجربه خود را در استفاده از خدمات ابری گوگل چگونه ارزیابی می‌کنید؟

تازه کار متوسط ماهر

۲. پیشینه

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

App Engine دسترسی به سیستم‌های قالب‌بندی Django و Jinja2 را فراهم می‌کند و چیزی که این مثال را متفاوت می‌کند (علاوه بر اضافه کردن دسترسی Blobstore) این است که در ماژول 15 از Django در ماژول 0 به Jinja2 تغییر می‌کند. یک گام کلیدی در مدرن‌سازی برنامه‌های App Engine، مهاجرت چارچوب‌های وب از webapp2 به Flask است. دومی از Jinja2 به عنوان سیستم قالب‌بندی پیش‌فرض خود استفاده می‌کند، بنابراین ما با پیاده‌سازی Jinja2 در حالی که برای دسترسی Blobstore روی webapp2 باقی می‌مانیم، حرکت در این مسیر را آغاز می‌کنیم. از آنجایی که Flask به طور پیش‌فرض از Jinja2 استفاده می‌کند، این بدان معناست که در ماژول 16 نیازی به تغییر قالب نخواهد بود.

۳. تنظیمات/پیش‌پردازش

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

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

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

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

یکی از پیش‌نیازهای این آزمایشگاه کد، داشتن یک نمونه برنامه ماژول ۰ است که کار کند. اگر آن را ندارید، می‌توانید آن را از پوشه "START" ماژول ۰ (لینک زیر) دریافت کنید. این آزمایشگاه کد، شما را در هر مرحله راهنمایی می‌کند و در پایان، کدی مشابه آنچه در پوشه "FINISH" ماژول ۱۵ وجود دارد، ارائه می‌دهد.

دایرکتوری فایل‌های شروع ماژول ۰ باید به این شکل باشد:

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

۳. (دوباره) استقرار برنامه پایه

مراحل مقدماتی باقی مانده برای اجرا:

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

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

a7a9d2b80d706a2b.png

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

برنامه.yaml

هیچ تغییر اساسی در پیکربندی برنامه ایجاد نشده است، با این حال همانطور که قبلاً ذکر شد، ما از قالب‌بندی جنگو (پیش‌فرض) به 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 شامل اضافه شدن استفاده از API Blobstore و جایگزینی قالب‌بندی Django با Jinja2 است. در اینجا مواردی که تغییر می‌کنند را مشاهده می‌کنید:

  1. هدف ماژول os ایجاد یک نام مسیر فایل به یک الگوی جنگو است. از آنجایی که ما در حال انتقال به Jinja2 هستیم که این کار را انجام می‌دهد، استفاده از os و همچنین رندرکننده الگوی جنگو، google.appengine.ext.webapp.template ، دیگر مورد نیاز نیستند، بنابراین آنها حذف می‌شوند.
  2. API مربوط به Blobstore را وارد کنید: 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

تغییرات لیست بالا را با جایگزینی بخش import فعلی در 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)

در اینجا تصویری از تغییراتی که تاکنون ایجاد شده است را مشاهده می‌کنید:

۲۲۷۰۷۸۳۷۷۶۷۵۹f۷f.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 که در بالا توضیح داده شد، نیاز دارد.

قبل از این به‌روزرسانی‌ها، برنامه ماژول ۰ فقط یک هندلر اصلی با متد 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 ، ۲) یک هندلر دانلود "view blob" با متد 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 وجود دارد. این فراخوانی، 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 به برنامه نمونه Module 0 انجام شده است.

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

ذخیره‌سازی Blobstore در نهایت به خود Cloud Storage تبدیل شد. این بدان معناست که آپلودهای 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 کتابخانه استاندارد پایتون، برای تأیید نوع تصویر، اعتبارسنجی کنید. در نهایت، احتمالاً می‌خواهید اندازه فایل‌های آپلود شده را در صورت وجود عوامل مخرب محدود کنید .

بیایید فرض کنیم همه کارها انجام شده است. چگونه می‌توانیم برنامه خود را به‌روزرسانی کنیم تا از مشخص کردن محل ذخیره فایل‌های آپلود شده پشتیبانی کند؟ نکته کلیدی این است که فراخوانی blobstore.create_upload_url در MainHandler.get را تغییر دهیم تا با اضافه کردن پارامتر gs_bucket_name به این شکل، مکان مورد نظر در Cloud Storage برای آپلود مشخص شود:

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

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

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

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

برنامه خود را با استفاده از gcloud app deploy دوباره مستقر کنید و تأیید کنید که برنامه همانطور که تبلیغ شده کار می‌کند، و از نظر تجربه کاربری (UX) با برنامه Module 0 متفاوت است. اکنون دو صفحه مختلف در برنامه شما وجود دارد که اولین آنها فرم آپلود فایل بازدید است:

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

f5ac6b98ee8a34c.png

تبریک می‌گویم که این آزمایشگاه کدنویسی را با اضافه کردن استفاده از App Engine Blobstore به برنامه نمونه ماژول 0 به پایان رساندید. اکنون کد شما باید با آنچه در پوشه FINISH (ماژول 15) است مطابقت داشته باشد. فایل جایگزین main-gcs.py نیز در آن پوشه موجود است.

تمیز کردن

عمومی

اگر فعلاً کارتان تمام است، توصیه می‌کنیم برنامه App Engine خود را غیرفعال کنید تا از پرداخت هزینه جلوگیری شود. با این حال، اگر می‌خواهید بیشتر آزمایش یا تجربه کنید، پلتفرم App Engine سهمیه رایگان دارد و بنابراین تا زمانی که از آن سطح استفاده تجاوز نکنید، نباید هزینه‌ای از شما دریافت شود. این هزینه برای محاسبات است، اما ممکن است برای سرویس‌های مربوطه App Engine نیز هزینه‌هایی وجود داشته باشد، بنابراین برای اطلاعات بیشتر به صفحه قیمت‌گذاری آن مراجعه کنید. اگر این مهاجرت شامل سایر سرویس‌های ابری باشد، هزینه آنها جداگانه محاسبه می‌شود. در هر صورت، در صورت لزوم، به بخش "ویژه این 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 هستند. برای اطلاعات بیشتر به مستندات هر محصول مراجعه کنید:

مراحل بعدی

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

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

۷. منابع اضافی

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

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

منابع مهاجرت

لینک‌های پوشه‌های مخزن ماژول ۰ (START) و ماژول ۱۵ (FINISH) را می‌توانید در جدول زیر پیدا کنید. همچنین می‌توانید از مخزن تمام مهاجرت‌های Codelab مربوط به App Engine که می‌توانید آن‌ها را کلون کنید یا یک فایل ZIP دانلود کنید، به آن‌ها دسترسی داشته باشید.

کدلب

پایتون ۲

پایتون ۳

ماژول 0

کد

ناموجود

ماژول ۱۵ (این آزمایشگاه کد)

کد

ناموجود

منابع آنلاین

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

موتور برنامه

گوگل کلود

پایتون

ویدیوها

مجوز

این اثر تحت مجوز عمومی Creative Commons Attribution 2.0 منتشر شده است.