Pengendali Blobstore webapp

webapp menyertakan class pengendali permintaan untuk menangani Blobstore API. BlobstoreUploadHandler menyediakan logika untuk mengurai permintaan upload yang diteruskan melalui Blobstore ke dalam kumpulan data BlobInfo untuk diproses lebih lanjut. BlobstoreDownloadHandler memudahkan penyajian nilai Blobstore dari jalur mana pun.

BlobstoreUploadHandler

Nilai ditambahkan ke Blobstore melalui upload file yang diposting oleh pengguna atau administrator aplikasi. Aplikasi ini memposting formulir web dengan kolom upload file dan tindakan formulir yang mengarahkan upload ke Blobstore. Aplikasi mendapatkan URL tindakan formulir dengan memanggil fungsi (create_upload_url()), dengan meneruskan URL pengendali aplikasi yang akan dipanggil saat pengguna mengupload file. Aplikasi webapp dapat menggunakan subclass dari class BlobstoreUploadHandler sebagai pengendali untuk URL ini.

Metode get_uploads() menampilkan daftar objek BlobInfo, satu untuk setiap file yang diupload dalam permintaan. Setiap objek berisi kunci Blobstore untuk nilai yang diupload, serta metadata seperti nama file dan ukuran. Setiap file yang diupload juga memiliki entity yang sesuai di datastore dengan informasi ini, sehingga Anda dapat mengambil objek BlobInfo nanti dengan kunci blob, atau melakukan kueri datastore melalui kolom metadata. Pengendali upload akan mengurai informasi ini langsung dari data permintaan, bukan datastore.

Secara default, get_uploads() menampilkan objek BlobInfo untuk semua file yang diupload dalam permintaan. Metode ini juga menerima argumen field_name untuk mendapatkan hanya satu file (atau beberapa file) bagi kolom upload file tertentu. Nilai yang ditampilkan selalu berupa daftar, mungkin daftar kosong.

class PhotoUploadHandler(blobstore_handlers.BlobstoreUploadHandler):
    def post(self):
        upload = self.get_uploads()[0]
        user_photo = UserPhoto(
            user=users.get_current_user().user_id(),
            blob_key=upload.key())
        user_photo.put()

        self.redirect('/view_photo/%s' % upload.key())

Menggunakan BlobstoreUploadHandler dengan Google Cloud Storage

Jika menggunakan pengendali upload ini dengan Cloud Storage, Anda harus mendapatkan dan menyimpan nama lengkap file objek Cloud Storage, karena ini diperlukan untuk mengambil file lagi dari Cloud Storage. Gunakan fungsi get_file_infos, yang menampilkan kumpulan data FileInfo yang sesuai dengan setiap upload. Nama lengkap objek Cloud Storage, jenis konten, waktu pembuatan, dan data lainnya tersedia di FileInfo. (Lihat link untuk detail selengkapnya.)

BlobstoreDownloadHandler

Untuk menampilkan nilai Blobstore, aplikasi menetapkan header X-AppEngine-BlobKey ke nilai kunci Blobstore dalam bentuk string. Saat melihat header ini dalam respons, App Engine akan menampilkan nilai blob sebagai isi respons. Class pengendali webapp BlobstoreDownloadHandler memudahkan penetapan nilai ini dalam respons.

Metode send_blob() mengambil objek BlobKey, kunci string, atau BlobInfo sebagai argumen blob_key_or_info, dan menetapkan data respons sehingga nilai blob akan ditampilkan kepada pengguna. Metode ini mengambil argumen content_type opsional yang mengabaikan jenis konten MIME dari nilai blob yang tersimpan. Secara default, blob ditayangkan dengan jenis konten yang ditetapkan oleh klien yang menguploadnya, jenis konten yang berasal dari nama file, atau jenis umum jika tidak ada informasi jenis lain yang tersedia.

Metode send_blob() menerima argumen save_as yang menentukan apakah data blob dikirim sebagai data respons mentah atau sebagai lampiran MIME dengan nama file. Jika argumennya berupa string, blob akan dikirim sebagai lampiran, dan nilai string digunakan sebagai nama file. Jika True dan blob_key_or_info adalah objek BlobInfo, nama file dari objek akan digunakan. Secara default, data blob dikirim sebagai isi respons, bukan sebagai lampiran MIME.

class ViewPhotoHandler(blobstore_handlers.BlobstoreDownloadHandler):
    def get(self, photo_key):
        if not blobstore.get(photo_key):
            self.error(404)
        else:
            self.send_blob(photo_key)

Blobstore mendukung pengiriman sebagian nilai saja, bukan nilai penuh, yang dideskripsikan sebagai rentang indeks byte. Anda dapat memberikan rentang indeks byte ke metode send_blob() BlobstoreDownloadHandler dengan dua cara. Cara pertama adalah menentukan rentang sebagai argumen start dan end:

            # Send the first 1,000 bytes of the value.
            self.send_blob(key, start=0, end=999)

Secara default, BlobstoreDownloadHandler mengikuti header range dalam permintaan. Jika Anda ingin memblokir penggunaan header rentang asli, berikan parameter use_range=False ke send_blob():

            # Send the full value of the blob and
            # block the "range" header.
            self.send_blob(key, use_range=False)

Nilai header range adalah rentang byte HTTP standar. BlobstoreDownloadHandler menggunakan webob.byterange untuk mengurai nilai header ini.

Menyelesaikan aplikasi contoh

Dalam aplikasi contoh berikut, URL utama aplikasi memuat formulir yang meminta pengguna mengupload file, dan pengendali upload segera memanggil pengendali download untuk menyalurkan data. Ini dilakukan untuk menyederhanakan aplikasi contoh. Dalam praktiknya, Anda mungkin tidak akan menggunakan URL utama untuk meminta upload data, dan Anda juga tidak akan langsung menampilkan blob yang baru saja diupload.

from google.appengine.api import users
from google.appengine.ext import blobstore
from google.appengine.ext import ndb
from google.appengine.ext.webapp import blobstore_handlers
import webapp2


# This datastore model keeps track of which users uploaded which photos.
class UserPhoto(ndb.Model):
    user = ndb.StringProperty()
    blob_key = ndb.BlobKeyProperty()


class PhotoUploadFormHandler(webapp2.RequestHandler):
    def get(self):
        upload_url = blobstore.create_upload_url('/upload_photo')
        # To upload files to the blobstore, the request method must be "POST"
        # and enctype must be set to "multipart/form-data".
        self.response.out.write("""
<html><body>
<form action="{0}" method="POST" enctype="multipart/form-data">
  Upload File: <input type="file" name="file"><br>
  <input type="submit" name="submit" value="Submit">
</form>
</body></html>""".format(upload_url))


class PhotoUploadHandler(blobstore_handlers.BlobstoreUploadHandler):
    def post(self):
        upload = self.get_uploads()[0]
        user_photo = UserPhoto(
            user=users.get_current_user().user_id(),
            blob_key=upload.key())
        user_photo.put()

        self.redirect('/view_photo/%s' % upload.key())


class ViewPhotoHandler(blobstore_handlers.BlobstoreDownloadHandler):
    def get(self, photo_key):
        if not blobstore.get(photo_key):
            self.error(404)
        else:
            self.send_blob(photo_key)


app = webapp2.WSGIApplication([
    ('/', PhotoUploadFormHandler),
    ('/upload_photo', PhotoUploadHandler),
    ('/view_photo/([^/]+)?', ViewPhotoHandler),
], debug=True)