1. ภาพรวม
ชุดโปรแกรม Codelab สำหรับการย้ายข้อมูลแบบ Serverless (บทแนะนำแบบลงมือทำด้วยตนเอง) และวิดีโอที่เกี่ยวข้องมีจุดประสงค์เพื่อช่วยให้นักพัฒนาแอป Google Cloud Serverless ปรับการดำเนินการให้ทันสมัยได้ด้วยคำแนะนำการย้ายข้อมูลอย่างน้อย 1 รายการ โดยให้ย้ายออกจากบริการเดิมเป็นหลัก การดำเนินการดังกล่าวทำให้แอปพกพาไปได้ทุกที่ รวมถึงมอบตัวเลือกและความยืดหยุ่นที่มากขึ้น ทำให้สามารถผสานรวมและเข้าถึงผลิตภัณฑ์ Cloud ที่หลากหลายยิ่งขึ้น และอัปเกรดเป็นรุ่นภาษาใหม่ๆ ได้ง่ายยิ่งขึ้น แม้ว่าในช่วงแรกจะมุ่งเน้นที่ผู้ใช้ Cloud รุ่นแรกสุด ซึ่งเป็นนักพัฒนา App Engine (สภาพแวดล้อมมาตรฐาน) เป็นหลัก แต่ชุดโซลูชันนี้ก็กว้างพอที่จะรวมแพลตฟอร์มแบบ Serverless อื่นๆ เช่น Cloud Functions และ Cloud Run หรือแพลตฟอร์มอื่นๆ ที่เกี่ยวข้อง
Codelab ของโมดูล 15 นี้อธิบายถึงวิธีเพิ่มการใช้งาน App Engine blobstore
ไปยังแอปตัวอย่างจากโมดูล 0 จากนั้นคุณจึงจะพร้อมย้ายข้อมูลการใช้งานดังกล่าวไปยัง Cloud Storage ในโมดูล 16 ถัดไป
คุณจะได้เรียนรู้วิธีต่อไปนี้
- เพิ่มการใช้ API/ไลบรารี App Engine Blobstore
- จัดเก็บการอัปโหลดของผู้ใช้ไปยังบริการ
blobstore
- เตรียมการสำหรับขั้นตอนถัดไปในการย้ายข้อมูลไปยัง Cloud Storage
สิ่งที่ต้องมี
- โปรเจ็กต์ Google Cloud Platform ที่มีบัญชีสำหรับการเรียกเก็บเงิน GCP ที่ใช้งานอยู่
- ทักษะพื้นฐานเรื่อง Python
- ความรู้เกี่ยวกับคำสั่งทั่วไปของ Linux
- ความรู้พื้นฐานเกี่ยวกับการพัฒนาและการทำให้แอป App Engine ใช้งานได้
- แอป App Engine โมดูล 0 ที่ใช้งานได้ (มาจากที่เก็บ)
แบบสำรวจ
คุณจะใช้บทแนะนำนี้อย่างไร
คุณจะให้คะแนนประสบการณ์การใช้งาน Python อย่างไร
คุณจะให้คะแนนความพึงพอใจในการใช้บริการ Google Cloud อย่างไร
2. ข้อมูลเบื้องต้น
หากต้องการย้ายข้อมูลจาก App Engine Blobstore API ให้เพิ่มการใช้งานในแอป App Engine ndb
ซึ่งเป็นพื้นฐานที่มีอยู่จากโมดูล 0 แอปตัวอย่างจะแสดงการเข้าชม 10 ครั้งล่าสุดของผู้ใช้ เรากำลังแก้ไขแอปเพื่อแจ้งให้ผู้ใช้ปลายทางอัปโหลดอาร์ติแฟกต์ (ไฟล์) ที่ตรงกับ "การเข้าชม" ของตน หากผู้ใช้ไม่ต้องการทำเช่นนั้น สามารถกด "ข้าม" ตัวเลือก ไม่ว่าผู้ใช้จะตัดสินใจอย่างไร หน้าถัดไปจะแสดงผลเหมือนกับแอปจากโมดูล 0 (และโมดูลอื่นๆ อีกหลายโมดูลในชุดนี้) เมื่อใช้การผสานรวม App Engine blobstore
นี้แล้ว เราจะย้ายข้อมูลไปยัง Cloud Storage ได้ใน Codelab (โมดูล 16) ถัดไป
App Engine ให้สิทธิ์เข้าถึงระบบเทมเพลตของ Django และ Jinja2 และสิ่งหนึ่งที่ทำให้ตัวอย่างนี้แตกต่างออกไป (นอกเหนือจากการเพิ่มการเข้าถึง Blobstore) คือเปลี่ยนจากการใช้ Django ในโมดูล 0 ไปเป็น Jinja2 ในโมดูล 15 ขั้นตอนสำคัญในการปรับแอป App Engine ให้ทันสมัยคือการย้ายข้อมูลเฟรมเวิร์กเว็บจาก webapp2
ไปยัง Flask เครื่องหลังใช้ Jinja2 เป็นระบบเทมเพลตเริ่มต้น เราจึงเริ่มดำเนินการในทิศทางนั้นด้วยการใช้ Jinja2 ขณะที่ใช้ webapp2
สำหรับการเข้าถึง Blobstore ต่อไป เนื่องจาก Flask ใช้ Jinja2 โดยค่าเริ่มต้น จึงไม่ต้องมีการเปลี่ยนแปลงเทมเพลตในโมดูล 16 แต่อย่างใด
3. การตั้งค่า/งานล่วงหน้า
ก่อนจะไปยังส่วนหลักของบทแนะนำ ให้ตั้งค่าโปรเจ็กต์ รับโค้ด และทำให้แอปพื้นฐานใช้งานได้เพื่อเริ่มต้นกับโค้ดที่ใช้งานได้
1. สร้างโปรเจ็กต์
หากคุณทำให้แอปโมดูล 0 ใช้งานได้แล้ว เราขอแนะนำให้ใช้โปรเจ็กต์ (และโค้ด) เดียวกันซ้ำ หรือคุณจะสร้างโปรเจ็กต์ใหม่หรือนำโปรเจ็กต์อื่นที่มีอยู่มาใช้ใหม่ก็ได้ ตรวจสอบว่าโปรเจ็กต์มีบัญชีสำหรับการเรียกเก็บเงินที่ใช้งานอยู่และเปิดใช้ App Engine แล้ว
2. รับแอปตัวอย่างพื้นฐาน
ข้อกำหนดเบื้องต้นอย่างหนึ่งของ Codelab นี้คือแอปตัวอย่างโมดูล 0 ที่ใช้งานได้ หากยังไม่มี คุณสามารถรับได้จากโมดูล 0 "START" (ลิงก์ด้านล่าง) Codelab นี้จะแนะนำคุณทีละขั้นตอน สรุปด้วยโค้ดที่คล้ายกับสิ่งที่อยู่ในโมดูล 15 "FINISH" โฟลเดอร์
- START: โฟลเดอร์โมดูล 0 (Python 2)
- FINISH: โฟลเดอร์โมดูล 15 (Python 2)
- ทั้งที่เก็บ (เพื่อโคลนหรือดาวน์โหลดไฟล์ ZIP)
ไดเรกทอรีของไฟล์ STARTing โมดูล 0 ควรมีลักษณะดังนี้
$ ls README.md index.html app.yaml main.py
3. (อีกครั้ง) ทำให้แอปพื้นฐานใช้งานได้
ขั้นตอนก่อนการทำงานที่เหลือของคุณที่ต้องดำเนินการตอนนี้มีดังนี้
- ทำความคุ้นเคยกับเครื่องมือบรรทัดคำสั่ง
gcloud
- ทำให้แอปตัวอย่างใช้งานได้อีกครั้งกับ
gcloud app deploy
- ยืนยันว่าแอปทำงานบน App Engine โดยไม่มีปัญหา
เมื่อคุณดำเนินการขั้นตอนเหล่านี้เสร็จเรียบร้อยและเห็นว่าเว็บแอปทำงานแล้ว (โดยมีเอาต์พุตคล้ายกับด้านล่าง) คุณก็พร้อมที่จะเพิ่มการแคชในแอปแล้ว
4. อัปเดตไฟล์การกำหนดค่า
app.yaml
การกำหนดค่าแอปพลิเคชันจะไม่มีการเปลี่ยนแปลงเนื้อหา แต่ดังที่ได้กล่าวไว้ก่อนหน้านี้ เรากำลังย้ายจากเทมเพลตของ Django (ค่าเริ่มต้น) ไปยัง Jinja2 ดังนั้นในการสลับ ผู้ใช้ควรระบุ Jinja2 เวอร์ชันล่าสุดที่มีในเซิร์ฟเวอร์ App Engine และทำได้โดยการเพิ่มลงในส่วนไลบรารีบุคคลที่สามในตัวของ app.yaml
ก่อนหน้า:
runtime: python27
threadsafe: yes
api_version: 1
handlers:
- url: /.*
script: main.app
แก้ไขไฟล์ app.yaml
โดยเพิ่มส่วน libraries
ใหม่ดังที่แสดงที่นี่
หลัง:
runtime: python27
threadsafe: yes
api_version: 1
handlers:
- url: /.*
script: main.app
libraries:
- name: jinja2
version: latest
ไม่มีไฟล์การกำหนดค่าอื่นๆ ที่ต้องอัปเดต ดังนั้นให้ข้ามไปที่ไฟล์แอปพลิเคชัน
5. แก้ไขไฟล์แอปพลิเคชัน
การนำเข้าและการสนับสนุน Jinja2
การเปลี่ยนแปลงชุดแรกของ main.py
ได้แก่ การเพิ่มการใช้ Blobstore API และการแทนที่เทมเพลตของ Django ด้วย Jinja2 สิ่งที่จะเปลี่ยนแปลงมีดังนี้
- วัตถุประสงค์ของโมดูล
os
คือการสร้างชื่อพาธไฟล์ไปยังเทมเพลต Django เนื่องจากเรากำลังจะเปลี่ยนไปใช้ Jinja2 ที่จัดการปัญหานี้ จึงไม่จำเป็นต้องใช้os
รวมถึงตัวแสดงผลเทมเพลต Django ชื่อgoogle.appengine.ext.webapp.template
อีกต่อไป เราจึงจะนำออก - นำเข้า Blobstore API:
google.appengine.ext.blobstore
- นำเข้าเครื่องจัดการ Blobstore ที่พบในเฟรมเวิร์ก
webapp
ดั้งเดิม ซึ่งไม่มีอยู่ในwebapp2
:google.appengine.ext.webapp.blobstore_handlers
- นำเข้าการสนับสนุน 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
ตัวอย่างนี้แตกต่างจากการย้ายข้อมูลอื่นๆ ในซีรีส์นี้ตรงที่เราทำให้ฟังก์ชันหรือเอาต์พุตของแอปตัวอย่างเหมือนกัน (หรือเกือบเหมือนกัน) โดยไม่เปลี่ยนแปลง UX (มาก) ตรงที่ตัวอย่างนี้แตกต่างจากเวอร์ชันปกติมากกว่า แทนที่จะบันทึกการเข้าชมใหม่ในทันทีแล้วแสดง 10 รายการล่าสุด เรากำลังอัปเดตแอปเพื่อขอให้ผู้ใช้เก็บอาร์ติแฟกต์เพื่อลงทะเบียนการเข้าชมของพวกเขาด้วย จากนั้นผู้ใช้ปลายทางจะอัปโหลดไฟล์ที่เกี่ยวข้องหรือเลือก "ข้าม" ก็ได้ เพื่อที่จะไม่อัปโหลดอะไรเลย เมื่อขั้นตอนนี้เสร็จสมบูรณ์แล้ว "การเข้าชมล่าสุด" จะปรากฏขึ้น
การเปลี่ยนแปลงนี้ทำให้แอปของเราใช้บริการ 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)
ด้านล่างนี้เป็นภาพประกอบการเปลี่ยนแปลงต่างๆ ที่เกิดขึ้นจนถึงปัจจุบัน
รองรับการอัปโหลดไฟล์
การเปลี่ยนแปลงที่สำคัญที่สุดของฟังก์ชันการทำงานคือการรองรับการอัปโหลดไฟล์ ไม่ว่าจะเป็นการแจ้งให้ผู้ใช้อัปโหลดไฟล์ การรองรับ "การข้าม" หรือแสดงผลไฟล์ที่เกี่ยวข้องกับการเข้าชม ทั้งหมดนั้นเป็นส่วนหนึ่งของภาพ การเปลี่ยนแปลงที่จำเป็นต่อการรองรับการอัปโหลดไฟล์มีดังนี้
- คำขอตัวแฮนเดิลหลัก
GET
จะไม่ดึงข้อมูลการเข้าชมล่าสุดเพื่อแสดงอีกต่อไป แต่จะแจ้งให้ผู้ใช้อัปโหลดแทน - เมื่อผู้ใช้ปลายทางส่งไฟล์เพื่ออัปโหลดหรือข้ามกระบวนการนั้น
POST
จากแบบฟอร์มจะส่งตัวควบคุมไปยังUploadHandler
ใหม่ ซึ่งได้มาจากgoogle.appengine.ext.webapp.blobstore_handlers.BlobstoreUploadHandler
- เมธอด
POST
ของUploadHandler
จะทำการอัปโหลด เรียกstore_visit()
เพื่อลงทะเบียนการเข้าชม และเรียกใช้การเปลี่ยนเส้นทาง HTTP 307 เพื่อส่งผู้ใช้กลับไปที่ "/" โดยที่... - ระบบจะค้นหาเมธอด
POST
ของตัวแฮนเดิลหลักสำหรับ (ผ่านfetch_visits()
) และแสดงการเข้าชมล่าสุด หากผู้ใช้เลือก "ข้าม" ไม่มีการอัปโหลดไฟล์ แต่การเข้าชมจะยังคงได้รับการลงทะเบียน ตามด้วยการเปลี่ยนเส้นทางเดียวกัน - การแสดงการเข้าชมล่าสุดจะมีฟิลด์ใหม่ที่แสดงให้ผู้ใช้เห็น ซึ่งอาจเป็น "มุมมอง" แบบไฮเปอร์ลิงก์ หากมีไฟล์ที่อัปโหลดอยู่หรือ "ไม่มี" หรือไม่เช่นนั้น การเปลี่ยนแปลงเหล่านี้เกิดขึ้นในเทมเพลต HTML พร้อมกับการเพิ่มแบบฟอร์มการอัปโหลด (จะมีการดูข้อมูลเพิ่มเติมเกี่ยวกับเรื่องนี้ในเร็วๆ นี้)
- หากผู้ใช้ปลายทางคลิก "ดู" ลิงก์ของการเข้าชมที่มีวิดีโอที่อัปโหลดจะส่งคำขอ
GET
ไปยังViewBlobHandler
ใหม่ ซึ่งได้มาจากgoogle.appengine.ext.webapp.blobstore_handlers.BlobstoreDownloadHandler
โดยอาจแสดงผลไฟล์หากเป็นรูปภาพ (ในเบราว์เซอร์ หากมีการรองรับ) แจ้งให้ดาวน์โหลดหากไม่พบ หรือแสดงผลข้อผิดพลาด HTTP 404 หากไม่พบ - นอกเหนือจากคลาสของตัวแฮนเดิลคู่ใหม่และเส้นทางคู่ใหม่เพื่อส่งการรับส่งข้อมูลไป ตัวแฮนเดิลหลักต้องใช้เมธอด
POST
ใหม่เพื่อรับการเปลี่ยนเส้นทาง 307 ตามที่อธิบายไว้ข้างต้น
ก่อนการอัปเดตเหล่านี้ แอปโมดูล 0 จะแนะนำเพียงตัวแฮนเดิลหลักที่มีเมธอด GET
และเส้นทางเดียว ดังนี้
ก่อนหน้า:
class MainHandler(webapp2.RequestHandler):
'main application (GET) handler'
def get(self):
store_visit(self.request.remote_addr, self.request.user_agent)
visits = fetch_visits(10)
tmpl = os.path.join(os.path.dirname(__file__), 'index.html')
self.response.out.write(template.render(tmpl, {'visits': visits}))
app = webapp2.WSGIApplication([
('/', MainHandler),
], debug=True)
เมื่อติดตั้งอัปเดตเหล่านั้นแล้ว ตอนนี้จึงมี 3 ตัวแฮนเดิล ได้แก่ 1) เครื่องจัดการการอัปโหลดที่มีเมธอด POST
2) "ดู Blob" เครื่องจัดการการดาวน์โหลดที่มีเมธอด GET
และ 3) เครื่องจัดการหลักที่มีเมธอด GET
และ POST
ทำการเปลี่ยนแปลงเหล่านี้เพื่อให้ส่วนที่เหลือของแอปมีลักษณะเหมือนด้านล่างนี้
หลัง:
class UploadHandler(blobstore_handlers.BlobstoreUploadHandler):
'Upload blob (POST) handler'
def post(self):
uploads = self.get_uploads()
blob_id = uploads[0].key() if uploads else None
store_visit(self.request.remote_addr, self.request.user_agent, blob_id)
self.redirect('/', code=307)
class ViewBlobHandler(blobstore_handlers.BlobstoreDownloadHandler):
'view uploaded blob (GET) handler'
def get(self, blob_key):
self.send_blob(blob_key) if blobstore.get(blob_key) else self.error(404)
class MainHandler(BaseHandler):
'main application (GET/POST) handler'
def get(self):
self.render_response('index.html',
upload_url=blobstore.create_upload_url('/upload'))
def post(self):
visits = fetch_visits(10)
self.render_response('index.html', visits=visits)
app = webapp2.WSGIApplication([
('/', MainHandler),
('/upload', UploadHandler),
('/view/([^/]+)?', ViewBlobHandler),
], debug=True)
มีการเรียกที่สำคัญหลายรายการในโค้ดนี้ที่เราเพิ่งเพิ่ม:
- ในอีก
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
ของไฟล์จะส่งผลให้ระบบดึงข้อมูลไฟล์และส่งต่อไปยังเบราว์เซอร์ของผู้ใช้ปลายทาง
การเรียกเหล่านี้หมายถึงการเข้าถึงฟีเจอร์ที่เพิ่มลงในแอปจำนวนมาก นี่คือภาพของการเปลี่ยนแปลงชุดที่ 2 และชุดสุดท้ายใน main.py
อัปเดตเทมเพลต HTML
การอัปเดตแอปพลิเคชันหลักบางอย่างจะส่งผลต่ออินเทอร์เฟซผู้ใช้ (UI) ของแอป จึงต้องทำการเปลี่ยนแปลงที่เกี่ยวข้องกันในเทมเพลตเว็บ ซึ่งที่จริงแล้วมี 2 อย่างคือ
- แบบฟอร์มอัปโหลดไฟล์จำเป็นต้องมีองค์ประกอบอินพุต 3 อย่าง ได้แก่ ไฟล์ 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
การเปลี่ยนแปลงสุดท้ายอย่างหนึ่งคือ Jinja2 ต้องการเทมเพลตในโฟลเดอร์ templates
ดังนั้นให้สร้างโฟลเดอร์นั้นและย้าย index.html
เข้าไปใหม่ การย้ายครั้งสุดท้ายนี้ถือว่าคุณทำการเปลี่ยนแปลงที่จำเป็นทั้งหมดสำหรับการเพิ่มการใช้ Blobstore ในแอปตัวอย่างโมดูล 0 แล้ว
(ไม่บังคับ) "การเพิ่มประสิทธิภาพ" Cloud Storage
ต่อมา พื้นที่เก็บข้อมูลของ Blobstore ได้กลายเป็น Cloud Storage เอง ซึ่งหมายความว่าการอัปโหลด Blobstore จะปรากฏใน Cloud Console โดยเฉพาะเบราว์เซอร์ Cloud Storage คำถามก็คือตำแหน่ง คำตอบคือที่เก็บข้อมูล Cloud Storage เริ่มต้นของแอป App Engine ชื่อนี้คือชื่อโดเมนแบบเต็มของแอป App Engine PROJECT_ID
.appspot.com
ซึ่งสะดวกมากเพราะรหัสโปรเจ็กต์ทั้งหมดจะไม่ซ้ำกันใช่ไหม
การอัปเดตที่ทำกับแอปพลิเคชันตัวอย่างจะใส่ไฟล์ที่อัปโหลดลงในที่เก็บข้อมูล แต่นักพัฒนาซอฟต์แวร์มีตัวเลือกในการเลือกตำแหน่งที่เฉพาะเจาะจงมากขึ้นได้ ที่เก็บข้อมูลเริ่มต้นจะเข้าถึงได้โดยใช้โปรแกรมผ่าน google.appengine.api.app_identity.get_default_gcs_bucket_name()
ซึ่งจำเป็นต้องมีการนำเข้าใหม่หากคุณต้องการเข้าถึงค่านี้ เช่น ใช้เป็นคำนำหน้าสำหรับการจัดระเบียบไฟล์ที่อัปโหลด เช่น การจัดเรียงตามประเภทไฟล์ดังนี้
ตัวอย่างเช่น หากต้องการใช้งานในลักษณะดังกล่าวกับรูปภาพ คุณจะมีโค้ดลักษณะนี้พร้อมกับโค้ดที่จะตรวจสอบประเภทไฟล์เพื่อเลือกชื่อที่เก็บข้อมูลที่ต้องการ
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
6. สรุป/ล้างข้อมูล
ส่วนนี้จะสรุป Codelab นี้โดยการทำให้แอปใช้งานได้ ซึ่งจะช่วยยืนยันว่าแอปทำงานได้ตามที่ต้องการและอยู่ในเอาต์พุตที่แสดงขึ้น หลังจากตรวจสอบแอปแล้ว ให้ทำตามขั้นตอนการทำความสะอาดและพิจารณาขั้นตอนถัดไป
ติดตั้งใช้งานและยืนยันแอปพลิเคชัน
ทำให้แอปใช้งานได้อีกครั้งด้วย gcloud app deploy
และยืนยันว่าแอปทำงานได้ตามที่โฆษณา ซึ่งแตกต่างจากประสบการณ์ของผู้ใช้ (UX) จากแอปโมดูล 0 ขณะนี้แอปของคุณมี 2 หน้าจอ หน้าจอแรกคือข้อความแจ้งแบบฟอร์มอัปโหลดไฟล์การเข้าชม
จากนั้น ผู้ใช้ปลายทางจะอัปโหลดไฟล์แล้วคลิก "ส่ง" หรือคลิก "ข้าม" เพื่อไม่อัปโหลดอะไรเลย ในทั้ง 2 กรณี ผลการค้นหาคือหน้าจอการเข้าชมล่าสุด ซึ่งเสริมด้วย "มุมมอง" ลิงก์หรือ "ไม่มี" ระหว่างการประทับเวลาการเข้าชมกับข้อมูลผู้เข้าชม
ขอแสดงความยินดีที่ Codelab นี้เสร็จสิ้นการเพิ่มการใช้ App Engine Blobstore ในแอปตัวอย่างโมดูล 0 ตอนนี้โค้ดควรตรงกับสิ่งที่อยู่ในโฟลเดอร์ FINISH (Module 15) มี main-gcs.py
สำรองในโฟลเดอร์นั้นด้วย
ล้างข้อมูล
ทั่วไป
หากดำเนินการเสร็จแล้ว เราขอแนะนำให้คุณปิดใช้แอป App Engine เพื่อหลีกเลี่ยงการเรียกเก็บเงิน อย่างไรก็ตาม หากคุณต้องการทดสอบหรือทดลองเพิ่มเติม แพลตฟอร์ม App Engine จะมีโควต้าฟรี และตราบใดที่คุณใช้งานไม่เกินระดับการใช้งานดังกล่าว เราก็จะไม่เรียกเก็บเงิน ค่าดังกล่าวมีไว้สําหรับการประมวลผล แต่ก็อาจมีการเรียกเก็บเงินค่าบริการ App Engine ที่เกี่ยวข้องด้วย ดังนั้นโปรดดูข้อมูลเพิ่มเติมในหน้าราคา หากการย้ายข้อมูลนี้เกี่ยวข้องกับบริการระบบคลาวด์อื่นๆ ระบบจะเรียกเก็บเงินแยกต่างหาก ในทั้ง 2 กรณี หากมี โปรดดูส่วน "เฉพาะสำหรับ Codelab นี้" ด้านล่าง
เพื่อการเปิดเผยข้อมูลทั้งหมด การทำให้ใช้งานได้กับแพลตฟอร์มการประมวลผลแบบ Serverless ของ 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
" หากแอปของคุณโฮสต์ในสหรัฐอเมริกา
ในทางกลับกัน หากคุณไม่ต้องการดำเนินการกับแอปพลิเคชันนี้หรือ Codelab การย้ายข้อมูลอื่นๆ ที่เกี่ยวข้องต่อไป และต้องการลบทุกอย่างออกทั้งหมด ให้ปิดโปรเจ็กต์
เฉพาะสำหรับ Codelab นี้
บริการในรายการด้านล่างเป็นบริการเฉพาะสำหรับ Codelab นี้ โปรดดูข้อมูลเพิ่มเติมในเอกสารประกอบของผลิตภัณฑ์แต่ละรายการ
- บริการ App Engine Blobstore อยู่ภายใต้โควต้าและขีดจำกัดข้อมูลที่จัดเก็บไว้ ดังนั้นโปรดตรวจสอบรวมถึงหน้าราคาสำหรับแพ็กเกจบริการเดิม
- บริการ App Engine Datastore ให้บริการโดย Cloud Datastore (Cloud Firestore ในโหมด Datastore) ซึ่งมีรุ่นฟรีเช่นกัน ดูข้อมูลเพิ่มเติมได้ที่หน้าราคา
ขั้นตอนถัดไป
การย้ายข้อมูลเชิงตรรกะถัดไปที่ต้องพิจารณานั้นกล่าวถึงในโมดูล 16 ซึ่งจะแสดงให้นักพัฒนาแอปเห็นถึงวิธีย้ายข้อมูลจากบริการ App Engine Blobstore เพื่อใช้ไลบรารีของไคลเอ็นต์ Cloud Storage ข้อดีของการอัปเกรด ได้แก่ การที่คุณเข้าถึงฟีเจอร์ Cloud Storage ได้มากขึ้น การทำความคุ้นเคยกับไลบรารีของไคลเอ็นต์ที่ใช้ได้กับแอปนอก App Engine ไม่ว่าจะเป็นใน Google Cloud, ระบบคลาวด์อื่นๆ หรือแม้แต่ภายในองค์กร ถ้าไม่ต้องการใช้ฟีเจอร์ทั้งหมดจาก Cloud Storage หรือกังวลเกี่ยวกับผลกระทบที่มีต่อค่าใช้จ่าย ก็ใช้ App Engine Blobstore ต่อไปได้
นอกเหนือจากโมดูล 16 แล้ว ยังมีการย้ายข้อมูลที่เป็นไปได้อื่นๆ จำนวนมาก เช่น Cloud NDB และ Cloud Datastore, Cloud Tasks หรือ Cloud Memorystore นอกจากนี้ยังมีการย้ายข้อมูลข้ามผลิตภัณฑ์ไปยัง Cloud Run และ Cloud Functions ด้วย ที่เก็บการย้ายข้อมูลจะแสดงตัวอย่างโค้ดทั้งหมด ลิงก์คุณไปยัง Codelab และวิดีโอทั้งหมดที่พร้อมใช้งาน รวมถึงให้คำแนะนำเกี่ยวกับการย้ายข้อมูลที่ควรพิจารณาและ "คำสั่ง" ที่เกี่ยวข้อง การย้ายข้อมูลได้
7. แหล่งข้อมูลเพิ่มเติม
ปัญหา/ความคิดเห็นของ Codelab
หากมีปัญหาใดๆ เกี่ยวกับ Codelab นี้ โปรดค้นหาปัญหาของคุณก่อนยื่น ลิงก์สำหรับค้นหาและสร้างปัญหาใหม่
ทรัพยากรการย้ายข้อมูล
คุณสามารถดูลิงก์ไปยังโฟลเดอร์ที่เก็บสำหรับโมดูล 0 (START) และโมดูล 15 (FINISH) ได้ในตารางด้านล่าง นอกจากนี้ยังเข้าถึงได้จากที่เก็บสำหรับการย้ายข้อมูล Codelab ทั้งหมดของ App Engine ซึ่งจะโคลนหรือดาวน์โหลดไฟล์ ZIP ได้
Codelab | Python 2 | Python 3 |
โมดูล 0 | ไม่มี | |
โมดูล 15 (Codelab นี้) | ไม่มี |
แหล่งข้อมูลออนไลน์
ด้านล่างนี้คือแหล่งข้อมูลออนไลน์ที่อาจเกี่ยวข้องกับบทแนะนำนี้
App Engine
- บริการ App Engine Blobstore
- โควต้าและขีดจำกัดของข้อมูลที่จัดเก็บของ App Engine
- เอกสารประกอบของ App Engine
- รันไทม์ของ Python 2 App Engine (สภาพแวดล้อมมาตรฐาน)
- การใช้ไลบรารีในตัวของ App Engine บน Python 2 App Engine
- ข้อมูลราคาและโควต้าของ App Engine
- เปิดตัวแพลตฟอร์ม App Engine รุ่นที่ 2 (2018)
- การเปรียบเทียบกับ แพลตฟอร์มรุ่นที่ 2
- การรองรับรันไทม์เดิมในระยะยาว
- ที่เก็บตัวอย่างการย้ายข้อมูลเอกสารประกอบ
- ที่เก็บตัวอย่างการย้ายข้อมูลที่ชุมชนเป็นผู้มีส่วนร่วม
Google Cloud
- 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
วิดีโอ
- สถานีย้ายข้อมูลแบบ Serverless
- การสำรวจแบบ Serverless
- สมัครใช้บริการ Google Cloud Tech
- สมัครใช้บริการ Google Developers
ใบอนุญาต
ผลงานนี้ได้รับอนุญาตภายใต้ใบอนุญาตทั่วไปครีเอทีฟคอมมอนส์แบบระบุแหล่งที่มา 2.0