【问题标题】:Use Django views for handling blobstore uploads使用 Django 视图处理 blobstore 上传
【发布时间】:2012-02-11 12:07:17
【问题描述】:

我更喜欢使用 Django 视图,而不是使用 AppEngine 中提供的 BlobstoreUploadHandler,这样我可以将所有 url 和视图函数放在一起。但是,我不知道如何获取上传文件的blob-key! (就像get_uploads() 为上传处理程序所做的那样)。我看到BlobstoreUploadHandler 使用request.params,但我认为Django 的Request 没有。

def upload_form(request):
    upload_url = blobstore.create_upload_url(reverse(upload_blob))
    output = '<html><body>'
    output += '<form action="%s" method="POST" enctype="multipart/form-data">' % upload_url)
    output += ('''Upload File: <input type="file" name="file"><br> <input type="submit"
        name="submit" value="Submit"> </form></body></html>''')

def upload_blob(request):
    print request
    # How to get the 'blob-key' from request?!

当我检查请求对象时,我得到的只是

<WSGIRequest
GET:<QueryDict: {}>,
POST:<QueryDict: {u'submit': [u'Submit']}>
# And COOKIES, META, etcetera

编辑:Request.FILES

我发现可以使用 Request.FILES 提取一些信息,它给出:

<MultiValueDict: {u'file': [<InMemoryUploadedFile: my_file (message/external-body)>]}>

但是,我假设 blobstore 仍然处理文件内容(这就是它说“content_type=message/external-body”的原因吗?),所以我仍然需要密钥。调用read() 会得到:

Content-Type: application/octet-stream
MIME-Version: 1.0
Content-Length: 17
Content-MD5: ZmQ3OTJhNjMzNGE0OTAzNGU4NjE5MDNmMGEwNjliMGE=
content-type: application/octet-stream
content-disposition: form-data; name="file"; filename="a1_blob"
X-AppEngine-Upload-Creation: 2012-02-12 22:11:49.643751

所以看起来 AppEngine 实际上用这个描述符替换了文件内容,但是 AppEngine 将密钥放在哪里?

我开始怀疑 blob-key 只是在不使用 webapp 框架时丢失了,因为 UploadedFile 对象没有 key() 方法。

【问题讨论】:

    标签: django google-app-engine


    【解决方案1】:

    我花了很长时间才找到,但是content_type: message/external-body 需要额外的参数,才能找到实际 文件,在AppEngine 的情况下,这是blob-key。但是,Django 不支持这些额外的 content_type 参数,因此在处理过程中确实丢失了它们。好像有补丁,不过我觉得 AppEngine Django 版本中还没有。

    https://code.djangoproject.com/ticket/13721

    【讨论】:

    • 是的,这可以解决我的问题,但我想我当时使用了另一种解决方法(因为我无法修补 AppEngine Django)
    【解决方案2】:

    我昨天也遇到了同样的问题。感谢您的帖子,我意识到问题出在 django 和他的班级观点上。我终于使用了自 2011 年以来的代码,它仍然有效。它不使用 BlobstoreUploadHandler,而是自动上传到 blobstore 后,从请求中获取 blob_infos。

    您可以从回调 django 函数或类中以下一种方式使用该函数(我最后没有在 Django 的类视图中尝试它,但我认为它会起作用。目前我正在从函数视图中使用它Django 及其请求):

    media_blobs = get_uploads(request, populate_post=True)
    

    函数是下一个:

    import cgi 
    from google.appengine.ext import blobstore
    def get_uploads(request, field_name=None, populate_post=False):
        """Get uploads sent to this handler.
        Args:
        field_name: Only select uploads that were sent as a specific field.
        populate_post: Add the non blob fields to request.POST
        Returns:
          A list of BlobInfo records corresponding to each upload.
          Empty list if there are no blob-info records for field_name.
        """
    
        if hasattr(request,'__uploads') == False:
            request.META['wsgi.input'].seek(0)
        ja = request.META['wsgi.input']
        fields = cgi.FieldStorage(request.META['wsgi.input'], environ=request.META)
    
        request.__uploads = {}
        if populate_post:
            request.POST = {}
    
        for key in fields.keys():
            field = fields[key]
            if isinstance(field, cgi.FieldStorage) and 'blob-key' in field.type_options:
                request.__uploads.setdefault(key, []).append(blobstore.parse_blob_info(field))
            elif populate_post:
                if isinstance(field, list):
                    request.POST[key] = [val.value for val in field]
                else:
                    request.POST[key] = field.value
        if field_name:
            try:
                return list(request.__uploads[field_name])
            except KeyError:
                return []
        else:
            results = []
            for uploads in request.__uploads.itervalues():
                results += uploads
            return results
    

    最后一个函数不是我的。我不记得三四年前我在哪里得到它。但我认为它会对某人有所帮助。

    更新:

    您也可以使用 webapp.WSGIApplication 的视图处理程序,同时使用 django。这种方式将允许您使用 BlobstoreUploadHandler 和 BlobstoreDownloadHandler(以视频流为例)。您只需要在 main.py 中添加视图类并创建其处理程序:

    class ServeVideoHandler(blobstore_handlers.BlobstoreDownloadHandler):
        def get(self, resource):
            ...
    
    downloader_handler = webapp.WSGIApplication([('/pathA/pathB/([A-Za-z0-9\-\=_]+)', ServeVideoHandler),], debug=True)
    

    在 app.yaml 中,在包含您的 django 应用的脚本 main.application 之前添加处理程序。

    - url: /pathA/pathB/(.+)
      script: main.downloader_handler
    

    【讨论】:

    • Ops,我没有注意到年份,但我认为它会帮助有同样问题的人。当然 Noio 已经解决了这个问题。
    【解决方案3】:

    关键信息不是直接在文件中,而是在file.blobstore_info.key()

    1. 将包含图片的表单发布到使用blobstore.create_upload_url() 创建的网址:

      from google.appengine.ext import blobstore
      
      upload_url = blobstore.create_upload_url('/add_image/')
      

    创建的 url 将图像保存在 blobstore 中并将请求(带有修改的文件对象)重定向到 /add_image/

    1. 为/add_image/定义一个url模式和视图并处理图像:

      def add_action_image(request):
          image = request.data.get('image')
          image_key = image.blobstore_info.key()
          ... addl' logic to save a record with the image_key...
      

    【讨论】:

      【解决方案4】:

      正如您所指出的,BlobstoreUploadHandler 是开源的,因此您可以看到他们用于从请求参数中解析密钥的逻辑。请注意,request.params 仅包含来自查询字符串和请求正文的变量(对于 POST 请求)。因此,您可能希望从 djnago 请求的 REQUEST 对象开始。

      【讨论】:

      • 问题是,在这个 Request 对象中,(在 SDK 中)我找不到与 blob 键相关的任何内容(请参阅有问题的编辑)。我想知道使用Django的WSGIRequest时它是否会丢失。
      猜你喜欢
      • 2017-06-19
      • 2021-08-20
      • 1970-01-01
      • 2011-07-13
      • 2011-09-19
      • 2012-03-20
      • 2014-04-29
      • 2014-02-07
      • 2023-03-25
      相关资源
      最近更新 更多