Skip to content

Instantly share code, notes, and snippets.

@ratpik
Last active December 21, 2015 12:49
Show Gist options
  • Save ratpik/6308307 to your computer and use it in GitHub Desktop.
Save ratpik/6308307 to your computer and use it in GitHub Desktop.
A simple way to workaround using HTTP PATCH with Django tastypie on models that contain an Image/File Field
'''
I faced a problem when sending a HTTP PATCH to django models containing an ImageField.
The same problem was discussed on the django-tastypie mailing list - https://groups.google.com/forum/?fromgroups#!topic/django-tastypie/cxrI6Cl1z4s
When PATCHing a resource, tasypie dehydrates the original object, merges the changed fields, and then simulates a PUT. This presents a problem for FileField and ImageField as dehydrating these fields produces a URL to the file, rather than the path relative to MEDIA_ROOT stored in the database. Therefore, after a PATCH to a model with FileFields, those fields will contain full URLs rather than relatives paths.
For example, consider a set up in which media for a site is served from http://media.example.com/. When PATCHing a resource containing a file field, a reference to "/directory/file.jpg" will be dehydrated to "http://media.example.com/directory/file.jpg" which is the value that will be written back to the database. - Nikolas Stevenson-Molnar,
The simplest solution I found to this was specifying a custom storage on the django image/file field. The PATCH always stores the relative file path. This works fine to store as well as retrieve using Django-Tastypie
This is possible because of the way tastypie dehydrates filefilds by looking at the url attribute in it. Reference to source - https://github.com/toastdriven/django-tastypie/blob/master/tastypie/fields.py
'''
#From http://stackoverflow.com/questions/1190697/django-filefield-with-upload-to-determined-at-runtime
def custom_file_path(instance, filename):
return '/'.join(['custom', instance.user.username, filename])
#http://stackoverflow.com/questions/1729051/django-upload-to-outside-of-media-root
from django.core.files.storage import FileSystemStorage
fs = FileSystemStorage(location='', base_url='')
from django.db import models
class MyModel(models.Model)
...
picture = models.ImageField(max_length=255, upload_to=custom_file_path, storage=fs, blank=True)
... #Rest of the django model
@mave99a
Copy link

mave99a commented Dec 24, 2013

This works, however in case you use another storage backend this will cause problem.

My work around is define CharField to overwrite the FileField which cause this Patch problem:

e.g.

class ProfileResource(MultipartResource, ModelResource):
avatar = fields.CharField(attribute= 'avatar') # overwrite the default behavior
avatar_url = fields.FileField(attribute= 'avatar') # use this as the real result

class Meta:
    queryset = UserProfile.objects.all()
    resource_name = 'profile'
    authorization = Authorization()
    include_resource_uri = False
    excludes = []
    filtering = {
    }

@teewuane
Copy link

@mave99a, does your fix require the MultipartResource to work? I've been trying and can't get this to work with my setup with just class MyResource(ModelResource):

Edit:

Nevermind, it was some caching that was preventing the change. This solution works great!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment