App Engine blobstore কীভাবে ব্যবহার করতে হয় (মডিউল ১৫)

১. এক নজরে

সার্ভারলেস মাইগ্রেশন স্টেশন সিরিজের কোডল্যাব (নিজের গতিতে, হাতে-কলমে টিউটোরিয়াল) এবং সম্পর্কিত ভিডিও Google Cloud সার্ভারলেস ডেভেলপারদের এক বা একাধিক মাইগ্রেশনের মাধ্যমে তাদের অ্যাপ্লিকেশন আধুনিকীকরণে সাহায্য করার উদ্দেশ্যে তৈরি করা হয়েছে, প্রাথমিকভাবে লিগ্যাসি পরিষেবা থেকে সরে আসার জন্য। এটি করলে আপনার অ্যাপ আরও পোর্টেবল হয়ে যায় এবং আপনি আরও বিকল্প ও সুবিধা পান, যার ফলে আপনি আরও বেশি রেঞ্জের Cloud প্রোডাক্টের সাথে ইন্টিগ্রেট ও অ্যাক্সেস করতে পারেন এবং আরও সহজে নতুন ভাষার রিলিজে আপগ্রেড করতে পারেন। প্রাথমিকভাবে Cloud-এর প্রথম দিকের ব্যবহারকারীদের উপর ফোকাস করা হলেও, মূলত App Engine (স্ট্যান্ডার্ড এনভায়রনমেন্ট) ডেভেলপারদের জন্য এই সিরিজটি যথেষ্ট বিস্তৃত যাতে Cloud Functions এবং Cloud Run-এর মতো অন্যান্য সার্ভারলেস প্ল্যাটফর্ম বা প্রযোজ্য হলে অন্য কোথাও অন্তর্ভুক্ত করা যায়।

এই মডিউল ১৫ কোডল্যাব ব্যাখ্যা করে যে কীভাবে মডিউল ০ থেকে স্যাম্পেল অ্যাপে App Engine blobstore ব্যবহার যোগ করতে হয়। তারপর আপনি মডিউল ১৬-এ সেই ব্যবহার Cloud Storage-এ মাইগ্রেট করার জন্য প্রস্তুত হবেন।

কীভাবে করতে হয় আপনি তা শিখবেন

  • App Engine Blobstore API/লাইব্রেরির ব্যবহার যোগ করা
  • blobstore পরিষেবায় ব্যবহারকারীর আপলোড করা কন্টেন্ট স্টোর করা
  • Cloud Storage-এ মাইগ্রেট করার জন্য পরবর্তী ধাপের প্রস্তুতি নিন

আপনার কী প্রয়োজন হবে

সমীক্ষা

আপনি এই টিউটোরিয়াল কীভাবে ব্যবহার করবেন?

শুধু এটি পড়ুন এটি পড়ুন এবং অনুশীলন সম্পূর্ণ করুন

Python-এর সাথে আপনার অভিজ্ঞতাকে আপনি কত রেটিং দেবেন?

শিক্ষানবিস ইন্টারমিডিয়েট দক্ষ

Google Cloud পরিষেবা ব্যবহার করার অভিজ্ঞতাকে আপনি কত রেটিং দেবেন?

শিক্ষানবিস ইন্টারমিডিয়েট দক্ষ

২. ব্যাকগ্রাউন্ড

App Engine Blobstore API থেকে মাইগ্রেট করতে, মডিউল ০ থেকে আগে থেকে থাকা বেসলাইন App Engine ndb অ্যাপে এর ব্যবহার যোগ করুন। স্যাম্পেল অ্যাপ ব্যবহারকারীকে সবচেয়ে সাম্প্রতিক দশটি ভিজিট দেখায়। আমরা অ্যাপটি পরিবর্তন করছি যাতে ব্যবহারকারীকে তার "ভিজিট" সম্পর্কিত একটি আর্টিফ্যাক্ট (একটি ফাইল) আপলোড করার জন্য প্রম্পট করা যায়। ব্যবহারকারী এটি করতে না চাইলে, "এড়িয়ে যান" বিকল্প রয়েছে। ব্যবহারকারীর সিদ্ধান্ত যাই হোক না কেন, পরবর্তী পৃষ্ঠাটি মডিউল ০ (এবং এই সিরিজের অন্যান্য অনেক মডিউল) থেকে অ্যাপের মতো একই আউটপুট দেখায়। এই App Engine blobstore ইন্টিগ্রেশন প্রয়োগ করার পরে, আমরা পরবর্তী (মডিউল ১৬) কোডল্যাবে এটি Cloud Storage-এ মাইগ্রেট করতে পারব।

App Engine Django এবং Jinja2 টেমপ্লেটিং সিস্টেমে অ্যাক্সেস প্রদান করে এবং একটি জিনিস যা এই উদাহরণটিকে আলাদা করে তোলে (Blobstore অ্যাক্সেস যোগ করা ছাড়াও) তা হল এটি মডিউল ০-এ Django ব্যবহার করা থেকে এখানে মডিউল ১৫-এ Jinja2-এ পরিবর্তন করে। App Engine অ্যাপ আধুনিকীকরণের একটি গুরুত্বপূর্ণ ধাপ হল webapp2 থেকে Flask-এ ওয়েব ফ্রেমওয়ার্ক মাইগ্রেট করা। পরেরটি ডিফল্ট টেমপ্লেটিং সিস্টেম হিসেবে Jinja2 ব্যবহার করে, তাই আমরা Blobstore অ্যাক্সেসের জন্য webapp2-এ থাকাকালীন Jinja2 প্রয়োগ করে সেই দিকে এগিয়ে যেতে শুরু করি। যেহেতু Flask ডিফল্ট হিসেবে Jinja2 ব্যবহার করে, তাই এর অর্থ হল মডিউল ১৬-এ টেমপ্লেটে কোনও পরিবর্তন করার প্রয়োজন হবে না।

৩. সেট-আপ/প্রিওয়ার্ক

টিউটোরিয়ালের মূল অংশে যাওয়ার আগে, আপনার প্রোজেক্ট সেট-আপ করুন, কোড পান এবং কাজ করছে এমন কোড দিয়ে শুরু করার জন্য বেসলাইন অ্যাপ ডিপ্লয় করুন।

১. প্রোজেক্ট সেট-আপ করুন

আপনি যদি আগে থেকেই Module 0 অ্যাপ ডিপ্লয় করে থাকেন, তাহলে আমরা একই প্রোজেক্ট (এবং কোড) আবার ব্যবহার করার সাজেশন দিই। এছাড়াও, আপনি একেবারে নতুন প্রোজেক্ট তৈরি করতে অথবা আগে থেকে থাকা অন্য প্রোজেক্ট আবার ব্যবহার করতে পারবেন। প্রোজেক্টে একটি অ্যাক্টিভ বিলিং অ্যাকাউন্ট আছে এবং App Engine চালু আছে কিনা তা নিশ্চিত করুন।

২. বেসলাইন স্যাম্পেল অ্যাপ ডাউনলোড করুন

এই কোডল্যাবের অন্যতম পূর্বশর্ত হল একটি কার্যকরী মডিউল ০ স্যাম্পেল অ্যাপ থাকা। আপনার কাছে এটি না থাকলে, আপনি এটি মডিউল ০ "START" ফোল্ডার (নিচে লিঙ্ক) থেকে পেতে পারেন। এই কোডল্যাব আপনাকে প্রতিটি ধাপের মাধ্যমে নিয়ে যায়, মডিউল ১৫ "শেষ" ফোল্ডারে যা আছে তার মতো কোড দিয়ে শেষ হয়।

মডিউল ০-এর 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-এ চলে যাচ্ছি, তাই পরিবর্তন করার জন্য, ব্যবহারকারীদের App Engine সার্ভারে উপলভ্য Jinja2-এর লেটেস্ট ভার্সন উল্লেখ করতে হবে এবং আপনি এটি app.yaml-এর বিল্ট-ইন থার্ড-পার্টি লাইব্রেরি বিভাগে যোগ করে করতে পারেন।

আগে:

runtime: python27
threadsafe: yes
api_version: 1

handlers:
- url: /.*
  script: main.app

এখানে যেমন দেখছেন, ঠিক সেইভাবে নতুন libraries বিভাগ যোগ করে আপনার app.yaml ফাইল এডিট করুন:

পরে:

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. আসল webapp ফ্রেমওয়ার্কে পাওয়া Blobstore হ্যান্ডলার ইমপোর্ট করুন—এগুলি webapp2-এ উপলভ্য নয়: google.appengine.ext.webapp.blobstore_handlers
  4. webapp2_extras প্যাকেজ থেকে Jinja2 সাপোর্ট ইমপোর্ট করুন

আগে:

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

ইমপোর্ট করার পরে, webapp2_extras ডকুমেন্টে যেভাবে উল্লেখ করা আছে সেই অনুযায়ী Jinja2-এর ব্যবহারকে সাপোর্ট করার জন্য কিছু বয়লারপ্লেট কোড যোগ করুন। নিম্নলিখিত কোড স্নিপেট Jinja2 কার্যকারিতার সাথে স্ট্যান্ডার্ড webapp2 অনুরোধ হ্যান্ডলার ক্লাসকে র‍্যাপ করে, তাই ইম্পোর্টের ঠিক পরে 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 সহায়তা যোগ করুন

এই সিরিজের অন্যান্য মাইগ্রেশনের মতো নয় যেখানে আমরা স্যাম্পেল অ্যাপের কার্যকারিতা বা আউটপুট একই (বা প্রায় একই) রাখি এবং UX-এ (বেশি) পরিবর্তন করি না, এই উদাহরণটি স্বাভাবিকের থেকে অনেক বেশি আলাদা। নতুন ভিজিট অবিলম্বে রেজিস্টার করে সাম্প্রতিক দশটি ভিজিট দেখানোর পরিবর্তে, আমরা অ্যাপটি আপডেট করছি যাতে ব্যবহারকারীকে তার ভিজিট রেজিস্টার করার জন্য একটি ফাইল আর্টিফ্যাক্ট দিতে বলা হয়। ব্যবহারকারীরা তখন হয় সংশ্লিষ্ট ফাইল আপলোড করতে পারেন অথবা কিছুই আপলোড না করতে চাইলে "এড়িয়ে যান" বিকল্প বেছে নিতে পারেন। এই ধাপটি সম্পূর্ণ হয়ে গেলে, "সবচেয়ে সাম্প্রতিক ভিজিট" পৃষ্ঠাটি দেখানো হয়।

এই পরিবর্তনের ফলে আমাদের অ্যাপ Blobstore পরিষেবা ব্যবহার করে সাম্প্রতিক ভিজিট করা পৃষ্ঠায় সেই ছবি বা অন্য ফাইলের ধরন স্টোর (এবং পরে রেন্ডার) করতে পারবে।

ডেটা মডেল আপডেট করুন এবং এর ব্যবহার প্রয়োগ করুন

আমরা আরও ডেটা স্টোর করছি, বিশেষ করে Blobstore-এ আপলোড করা ফাইলের আইডি ("BlobKey" নামে পরিচিত) স্টোর করার জন্য ডেটা মডেল আপডেট করছি এবং 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, google.appengine.ext.webapp.blobstore_handlers.BlobstoreUploadHandler থেকে প্রাপ্ত নতুন UploadHandler-এ কন্ট্রোল পাস করে।
  3. UploadHandler-এর POST পদ্ধতি আপলোড করে, ভিজিট রেজিস্টার করার জন্য store_visit()-কে কল করে এবং ব্যবহারকারীকে "/"-এ ফেরত পাঠানোর জন্য HTTP 307 রিডাইরেক্ট ট্রিগার করে, যেখানে...
  4. প্রধান হ্যান্ডলারের POST পদ্ধতি (fetch_visits()-এর মাধ্যমে) সাম্প্রতিকতম ভিজিট সম্পর্কে কোয়েরি করে এবং তা দেখায়। ব্যবহারকারী "এড়িয়ে যান" বিকল্প বেছে নিলে, কোনও ফাইল আপলোড করা হয় না, তবে একই রিডাইরেক্টের পরে ভিজিট রেজিস্টার করা হয়।
  5. সবচেয়ে সাম্প্রতিক ভিজিট ডিসপ্লেতে ব্যবহারকারীকে দেখানো একটি নতুন ফিল্ড অন্তর্ভুক্ত থাকে, আপলোড ফাইল উপলভ্য থাকলে হাইপারলিঙ্ক করা "দেখুন" অথবা অন্যথায় "কিছুই নয়"। এই পরিবর্তনগুলি HTML টেমপ্লেটে দেখা যাবে এবং এর সাথে একটি আপলোড ফর্মও যোগ করা হবে (এই বিষয়ে আরও তথ্য শীঘ্রই জানানো হবে)।
  6. কোনও ব্যবহারকারী আপলোড করা ভিডিও সহ কোনও ভিজিটের জন্য "দেখুন" লিঙ্কে ক্লিক করলে, এটি google.appengine.ext.webapp.blobstore_handlers.BlobstoreDownloadHandler থেকে প্রাপ্ত একটি নতুন ViewBlobHandler-এ GET অনুরোধ করে, ছবিটি রেন্ডার করে (ব্রাউজারে কাজ করলে), না হলে ডাউনলোড করার জন্য প্রম্পট করে অথবা খুঁজে না পেলে HTTP 404 ত্রুটি দেখায়।
  7. নতুন হ্যান্ডলার ক্লাসের পেয়ার এবং তাদের কাছে ট্রাফিক পাঠানোর জন্য নতুন রুটের পেয়ার ছাড়াও, উপরে বর্ণিত ৩০৭ রিডাইরেক্ট পাওয়ার জন্য প্রধান হ্যান্ডলারের একটি নতুন POST পদ্ধতি প্রয়োজন।

এইসব আপডেটের আগে, Module 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)

এইসব আপডেট প্রয়োগ করার পরে, এখন তিনটি হ্যান্ডলার আছে: ১) 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-কে কল করা হয়েছে। এই কলটি URL তৈরি করে, যেটিতে ফর্মটি POST করে, Blobstore-এ ফাইল পাঠানোর জন্য আপলোড হ্যান্ডলারকে কল করে।
  • UploadHandler.post-এ, blobstore_handlers.BlobstoreUploadHandler.get_uploads-কে কল করা হয়েছে। এটিই হল আসল ম্যাজিক যা ফাইলটিকে Blobstore-এ রাখে এবং সেই ফাইলের জন্য একটি অনন্য এবং স্থায়ী আইডি প্রদান করে, এটি হল BlobKey।
  • ViewBlobHandler.get-এ, ফাইলের BlobKey সহ blobstore_handlers.BlobstoreDownloadHandler.send কল করলে ফাইলটি ফেচ করা হয় এবং ব্যবহারকারীর ব্রাউজারে ফরওয়ার্ড করা হয়

এইসব কলের মাধ্যমে অ্যাপে যোগ করা ফিচার অ্যাক্সেস করার বেশিরভাগ কাজ করা হয়। 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 স্টোরেজ অবশেষে Cloud Storage-এ পরিণত হয়েছে। এর অর্থ হল, Blobstore-এ আপলোড করা ফাইল Cloud কনসোলে, বিশেষ করে Cloud Storage ব্রাউজারে দেখা যায়। প্রশ্ন হল, কোথায়? উত্তর হল আপনার App Engine অ্যাপের ডিফল্ট Cloud Storage বাকেট। এটির নাম হল আপনার 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')

এছাড়াও, আপনি Python Standard Library imghdr মডিউল-এর মতো টুল ব্যবহার করে আপলোড করা ছবি যাচাই করবেন যাতে ছবির ধরন কনফার্ম করা যায়। সবশেষে, আপনি হয়ত খারাপ অ্যাক্টরদের ক্ষেত্রে আপলোডের সাইজ সীমিত করতে চাইবেন।

ধরা যাক, এই সব কাজ করা হয়ে গেছে। আপলোড করা ফাইল কোথায় স্টোর করা হবে তা নির্দিষ্ট করার জন্য আমাদের অ্যাপ কীভাবে আপডেট করব? এর মূল বিষয় হল, আপলোডের জন্য Cloud Storage-এ কাঙ্ক্ষিত লোকেশন নির্দিষ্ট করতে MainHandler.get-এ blobstore.create_upload_url-এর কলকে টুইক করা, এর জন্য এইভাবে 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

৬. সারসংক্ষেপ/ক্লিন-আপ

এই বিভাগটি অ্যাপ ডিপ্লয় করে, এটি উদ্দেশ্য অনুযায়ী কাজ করে কিনা তা যাচাই করে এবং যেকোনও প্রতিফলিত আউটপুটে এই কোডল্যাবটি শেষ করে। অ্যাপ যাচাইকরণের পরে, কোনও ক্লিন-আপ ধাপ থাকলে তা সম্পূর্ণ করুন এবং পরবর্তী ধাপগুলি বিবেচনা করুন।

অ্যাপ্লিকেশন ডিপ্লয় ও যাচাই করুন

gcloud app deploy-এর সাথে আপনার অ্যাপ আবার ডিপ্লয় করুন এবং অ্যাপটি বিজ্ঞাপন অনুযায়ী কাজ করছে কিনা তা কনফার্ম করুন, যা মডিউল ০ অ্যাপ থেকে ব্যবহারকারীর অভিজ্ঞতা (UX)-এর ক্ষেত্রে আলাদা। আপনার অ্যাপে এখন দুটি আলাদা স্ক্রিন আছে, প্রথমটি হল ভিজিট ফাইল আপলোড ফর্ম প্রম্পট:

f5b5f9f19d8ae978.pngসেখান থেকে, ব্যবহারকারী হয় ফাইল আপলোড করে "জমা দিন" বিকল্পে ক্লিক করেন অথবা কিছু আপলোড না করতে চাইলে "এড়িয়ে যান" বিকল্পে ক্লিক করেন। যেকোনও ক্ষেত্রেই, ফলাফল হল সবচেয়ে সাম্প্রতিক ভিজিট স্ক্রিন, এখন ভিজিট টাইমস্ট্যাম্প ও ভিজিটর তথ্যের মধ্যে "দেখুন" লিঙ্ক বা "কিছুই নয়" সহ অগমেন্ট করা হয়েছে:

f5ac6b98ee8a34cb.png

মডিউল ০ স্যাম্পেল অ্যাপে App Engine Blobstore-এর ব্যবহার যোগ করার এই কোডল্যাব সম্পূর্ণ করার জন্য অভিনন্দন। আপনার কোড এখন FINISH (মডিউল ১৫) ফোল্ডারে যা আছে তার সাথে মিলতে হবে। বিকল্প main-gcs.py-ও সেই ফোল্ডারে আছে।

অপ্রয়োজনীয়গুলি মুছুন

সাধারণ

আপনার কাজ হয়ে গেলে, বিলিং এড়াতে আমরা আপনাকে App Engine অ্যাপ বন্ধ করে দিতে সাজেস্ট করি। তবে, আপনি যদি আরও পরীক্ষা করতে চান, তাহলে App Engine প্ল্যাটফর্মে ফ্রি কোটা আছে এবং আপনি ব্যবহারের সীমা অতিক্রম না করা পর্যন্ত আপনাকে চার্জ করা হবে না। এটি কম্পিউটের জন্য, তবে প্রাসঙ্গিক App Engine পরিষেবার জন্যও চার্জ প্রযোজ্য হতে পারে, তাই আরও তথ্যের জন্য এর দামের পৃষ্ঠা দেখুন। এই মাইগ্রেশনে অন্যান্য Cloud পরিষেবা অন্তর্ভুক্ত থাকলে, সেগুলির জন্য আলাদাভাবে বিল করা হয়। যেকোনও ক্ষেত্রে, প্রযোজ্য হলে, নিচে "এই কোডল্যাবের জন্য নির্দিষ্ট" বিভাগটি দেখুন।

সম্পূর্ণ তথ্য প্রকাশ করার জন্য, App Engine-এর মতো Google Cloud সার্ভারলেস কম্পিউট প্ল্যাটফর্মে ডিপ্লয় করার জন্য সামান্য বিল্ড ও স্টোরেজ খরচ হয়। Cloud Storage-এর মতো Cloud Build-এরও নিজস্ব ফ্রি কোটা আছে। সেই ছবি স্টোর করার জন্য কোটার কিছুটা অংশ ব্যবহার করা হয়। তবে, আপনি এমন কোনও অঞ্চলে বসবাস করতে পারেন যেখানে এই ধরনের ফ্রি টিয়ার নেই, তাই সম্ভাব্য খরচ কমাতে আপনার স্টোরেজ ব্যবহারের ব্যাপারে সচেতন থাকুন। নির্দিষ্ট 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 ক্লায়েন্ট লাইব্রেরিতে মাইগ্রেট করতে হয়। আপগ্রেড করার সুবিধার মধ্যে রয়েছে, আরও বেশি Cloud Storage ফিচার অ্যাক্সেস করতে পারা, App Engine-এর বাইরে অ্যাপের জন্য কাজ করে এমন ক্লায়েন্ট লাইব্রেরির সাথে পরিচিত হওয়া, তা Google Cloud, অন্যান্য ক্লাউড বা এমনকি অন-প্রিমিসেই হোক না কেন। Cloud Storage-এ উপলভ্য সব ফিচার আপনার প্রয়োজন নেই বলে মনে করলে অথবা এর ফলে খরচ বেড়ে যেতে পারে বলে চিন্তিত হলে, আপনি App Engine Blobstore-এ থেকে যেতে পারেন।

মডিউল ১৬-এর পরে Cloud NDB ও Cloud Datastore, Cloud Tasks বা Cloud Memorystore-এর মতো আরও অনেক মাইগ্রেশন করা সম্ভব। এছাড়াও, Cloud Run ও Cloud Functions-এ ক্রস-প্রোডাক্ট মাইগ্রেশন আছে। মাইগ্রেশন রেপো-তে সব কোড স্যাম্পেল, উপলভ্য সব কোডল্যাব ও ভিডিওর লিঙ্ক এবং কোন মাইগ্রেশন বিবেচনা করতে হবে ও মাইগ্রেশনের প্রাসঙ্গিক "ক্রম" সম্পর্কে নির্দেশিকা দেওয়া থাকে।

৭. অতিরিক্ত রিসোর্স

কোডল্যাব সংক্রান্ত সমস্যা/মতামত

এই কোডল্যাবে কোনও সমস্যা দেখতে পেলে, অভিযোগ জানানোর আগে আপনার সমস্যাটি সার্চ করে দেখুন। নতুন সমস্যা সার্চ ও তৈরি করার লিঙ্ক:

মাইগ্রেশন রিসোর্স

মডিউল ০ (শুরু) এবং মডিউল ১৫ (শেষ)-এর জন্য রেপো ফোল্ডারের লিঙ্ক নিচের টেবিলে পাওয়া যাবে। এছাড়াও, সব App Engine কোডল্যাব মাইগ্রেশনের জন্য রেপো থেকে এগুলি অ্যাক্সেস করা যেতে পারে, যা আপনি ক্লোন করতে বা ZIP ফাইল ডাউনলোড করতে পারেন।

Codelab

Python 2

Python 3

মডিউল ০

কোড

প্রযোজ্য নয়

মডিউল ১৫ (এই কোডল্যাব)

কোড

প্রযোজ্য নয়

অনলাইন রিসোর্স

এই টিউটোরিয়ালের জন্য প্রাসঙ্গিক হতে পারে এমন অনলাইন রিসোর্স নিচে দেওয়া হল:

App Engine

Google Cloud

Python

ভিডিও

লাইসেন্স

এই কাজটি Creative Commons Attribution 2.0 Generic License-এর অধীনে লাইসেন্সপ্রাপ্ত।