Getting Google App Engine blob info in Django view

2019-04-15 05:06发布

This is a follow up question for Django on Google App Engine: cannot upload images

I got part of the upload of images to GAE Blobstore working. Here's what I did:

In models.py I created a model PhotoFeature:

class PhotoFeature(models.Model):
    property = models.ForeignKey(
        Property,
        related_name = "photo_features"
    )
    caption = models.CharField(
        max_length = 100
    )
    blob_key = models.CharField(
        max_length = 100
    )

In admin.py I created an admin entry with an override for the rendering of the change_form to allow for insert of the correct action to the Blobstore upload url:

class PhotoFeatureAdmin(admin.ModelAdmin):
    list_display = ("property", "caption")
    form = PhotoFeatureForm

    def render_change_form(self, request, context, *args, **kwargs):
        from google.appengine.ext import blobstore
        if kwargs.has_key("add"):
            context['blobstore_url'] = blobstore.create_upload_url('/admin/add-photo-feature')
        else:
            context['blobstore_url'] = blobstore.create_upload_url('/admin/update-photo-feature')
        return super(PhotoFeatureAdmin, self).render_change_form(request, context, args, kwargs)

As I use standard Django, I want to use the Django views to process the result once GAE has updated the BlobStore in stead of BlobstoreUploadHandler. I created the following views (as per the render_change_form method) and updated urls.py:

def add_photo_feature(request):

def update_photo_feature(request):

This all works nicely but once I get into the view method I'm a bit lost. How do I get the Blob key from the request object so I can store it with PhotoFeature? I use standard Django, not Django non-rel. I found this related question but it appears not to contain a solution. I also inspected the request object which gets passed into the view but could not find anything relating to the blob key.

EDIT:

The Django request object contains a FILES dictionary which will give me an instance of InMemoryUploadedFile. I presume that somehow I should be able to retrieve the blob key from that...

EDIT 2:

Just to be clear: the uploaded photo appears in the Blobstore; that part works. It's just getting the key back from the Blobstore that's missing here.

EDIT 3:

As per Daniel's suggestion I added storage.py from the djangoappengine project which contains the suggested upload handler and added it to my SETTINGS.PY. This results in the following exception when trying to upload:

'BlobstoreFileUploadHandler' object has no attribute 'content_type_extra'

1条回答
唯我独甜
2楼-- · 2019-04-15 05:17

This is really tricky to fix. The best solution I have found is to use the file upload handler from the djangoappengine project (which is associated with django-nonrel, but does not depend on it). That should handle the required logic to put the blob key into request.FILES, as you'd expect in Django.

Edit

I'd forgotten that django-nonrel uses a patched version of Django, and one of the patches is here to add the content-type-extra field. You can replicate the functionality by subclassing the upload handler as follows:

from djangoappengine import storage
class BlobstoreFileUploadHandler(storage.BlobstoreFileUploadHandler):
    """Handler that adds blob key info to the file object."""

    def new_file(self, field_name, *args, **kwargs):
      # We need to re-process the POST data to get the blobkey info.
      meta = self.request.META
      meta['wsgi.input'].seek(0)
      fields = cgi.FieldStorage(meta['wsgi.input'], environ=meta)
      if field_name in fields:
          current_field = fields[field_name]
          self.content_type_extra = current_field.type_options
      super(BlobstoreFileUploadHandler, self).new_file(field_name,
                                                       *args, **kwargs)

and reference this subclass in your settings.py rather than the original.

查看更多
登录 后发表回答