Python 3용 Blobstore API

이 페이지에서는 표준 환경에 Python 3 런타임과 함께 기존 번들 서비스 중 하나인 Blobstore API를 사용하는 방법을 설명합니다. 앱은 Your app can access the bundled services through the Python 3용 App Engine 서비스 SDK를 통해 번들 서비스에 액세스할 수 있습니다.

개요

웹 앱은 Python 3에서 지원되지 않으므로 Blobstore 핸들러 코드를 Python 2에서 Python 3으로 마이그레이션할 때 최소한 몇 가지 사항을 변경해야 합니다. Python 3용 Blobstore API를 사용하려면 다음 사항에 유의하세요.

  • Blobstore 핸들러 클래스는 유틸리티 클래스입니다. 즉, 핸들러 클래스는 더 이상 웹 기반이 아니며 웹 앱 패키지(google.appengine.ext.webapp) 또는 이러한 핸들러 서브클래스의 webapp2.RequestHandler 매개변수에서 제공하는 blobstore_handlers 모듈을 사용할 수 없습니다.

  • Blobstore 핸들러 클래스의 모든 메서드를 사용하려면 WSGI environ 사전이 입력 매개변수로 필요합니다.

다음 섹션에서는 Flask 앱과 Python 프레임워크를 사용하지 않는 WSGI 앱에서 Python 3용 BlobstoreUploadHandlerBlobstoreDownloadHandler 클래스를 사용하는 방법을 보여줍니다. 코드 변경 차이를 자세히 알아보려면 Python 3 예시를 Python 2 예시 코드와 비교하면 됩니다.

예: Flask 앱

Python 3에서 Blobstore 핸들러 클래스는 google.appengine.ext.blobstore 모듈의 일부입니다. Flask 앱의 경우 BlobstoreUploadHandlerBlobstoreDownloadHandler 클래스의 메서드에 대한 모든 호출을 사용하려면 request.environ 사전(flask 모듈에서 가져오는 request)이 필요합니다.

Python 2(webapp2)와 Python 3(Flask)의 코드 변경사항을 비교합니다. Flask 앱에서 get_uploads()send_blob() 메서드에서 request.environ 매개변수를 사용하는 방법을 확인합니다.

Python 2(webapp2)

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)

Python 3(Flask)

class PhotoUploadHandler(blobstore.BlobstoreUploadHandler):
    def post(self):
        upload = self.get_uploads(request.environ)[0]
        photo = PhotoUpload(blob_key=upload.key())
        photo.put()

        return redirect("/view_photo/%s" % upload.key())


class ViewPhotoHandler(blobstore.BlobstoreDownloadHandler):
    def get(self, photo_key):
        if not blobstore.get(photo_key):
            return "Photo key not found", 404
        else:
            headers = self.send_blob(request.environ, photo_key)

            # Prevent Flask from setting a default content-type.
            # GAE sets it to a guessed type if the header is not set.
            headers["Content-Type"] = None
            return "", headers


@app.route("/view_photo/<photo_key>")
def view_photo(photo_key):
    """View photo given a key."""
    return ViewPhotoHandler().get(photo_key)


@app.route("/upload_photo", methods=["POST"])
def upload_photo():
    """Upload handler called by blobstore when a blob is uploaded in the test."""
    return PhotoUploadHandler().post()

Python 3(Flask)의 전체 코드 샘플을 보려면 GitHub를 참조하세요.

예: 웹 프레임워크가 없는 WSGI 앱

다음 Python 3(WSGI 앱) 코드에서는 웹 프레임워크가 없는 WSGI 앱에 Blobstore 핸들러 클래스를 사용할 때 environ 매개변수를 추가하는 방법을 보여줍니다. environ 매개변수가 get_uploads()send_blob() 메서드에서 사용되는 방식을 확인하고 Python 2 버전과 비교합니다.

Python 2

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)

Python 3

class UploadPhotoHandler(blobstore.BlobstoreUploadHandler):
    """Upload handler called by blobstore when a blob is uploaded in the test."""

    def post(self, environ):
        upload = self.get_uploads(environ)[0]
        user_photo = UserPhoto(blob_key=upload.key())
        user_photo.put()

        # Redirect to the '/view_photo/<Photo Key>' URL
        return (
            "",
            http.HTTPStatus.FOUND,
            [("Location", "/view_photo/%s" % upload.key())],
        )


class ViewPhotoHandler(blobstore.BlobstoreDownloadHandler):
    def get_photo(self, environ, photo_key):
        if not blobstore.get(photo_key):
            return "Photo key not found", http.HTTPStatus.NOT_FOUND, []
        else:
            return (
                "",
                http.HTTPStatus.OK,
                list(self.send_blob(environ, photo_key).items()),
            )

    def get(self, environ):
        photo_key = (environ["app.url_args"])[0]
        return self.get_photo(environ, photo_key)


# map urls to functions
urls = [
    (r"^$", UploadFormHandler),
    (r"upload_photo/?$", UploadPhotoHandler),
    (r"view_photo/(.+)$", ViewPhotoHandler),
]

Python 3(Flask)의 전체 코드 샘플을 보려면 GitHub를 참조하세요.