Question

Using Django REST framework's generic ListCreateAPIView, I've created an end point that I think should be able to upload photos via POST requests. I am modeling my code on this tutorial.

So far I have attempted to POST a file to this endpoint using both Android and curl, and observed the same behavior: a new record is created, but the file is not attached. Because the file is a required field, the server then returns a 500 error.

This question looks similar, but he's not using REST framework's generic views and I'm not sure why... I'd like to take advantage of them where applicable.

Here is my Django view:

class PhotoList(generics.ListCreateAPIView):
    model = Photo
    serializer_class = PhotoSerializer
    permission_classes = [
        permissions.AllowAny
    ]

...my model:

def get_unique_image_file_path(instance=None, filename='dummy.jpg'):
    """
    function to determine where to save images.  assigns a uuid (random string) to each and places it
    in the images subdirectory below media.  by default, we assume the file is a .jpg
    """
    ext = filename.split('.')[-1]
    filename = "%s.%s" % (uuid.uuid4(), ext)
    # TODO: 'images' is hard coded
    return os.path.join('images', filename)

class Photo(models.Model):
    post = models.ForeignKey(Post, related_name='photos', null=True, blank=True)
    image = models.ImageField(upload_to=get_unique_image_file_path)

    def get_image_abs_path(self):
        return os.path.join(settings.MEDIA_ROOT, self.image.name)

... and my serializer:

class PhotoSerializer(serializers.ModelSerializer):
    image = serializers.Field('image.url')

class Meta:
    model = Photo

Reproducing the bug

To generate the behavior, I POST to the server using the following curl command (exactly the same thing happens with my Android client code):

curl --form image=@test_image.jpg http://localhost:8000/rest_tutorial/photos

Looking into generics.ListCreateAPIView, the create() method looks like this:

# Copied from rest_framework.mixins.CreateModelMixin 

def create(self, request, *args, **kwargs):
    serializer = self.get_serializer(data=request.DATA, files=request.FILES)

    if serializer.is_valid():
        self.pre_save(serializer.object)
        self.object = serializer.save(force_insert=True)
        self.post_save(self.object, created=True)
        headers = self.get_success_headers(serializer.data)
        return Response(serializer.data, status=status.HTTP_201_CREATED,
                        headers=headers)

    return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

As I step through the above code in PyCharm's debugger, I can clearly see my file in the serializer's init_files field after serializer.get_serializer(). However, serializer's object field has a bunch of tracebacks but no references to my image file. Maybe something is wrong here?

After self.object = serializer.save(force_insert=True) the record is created with an empty image field, the file is not uploaded, and self.object.image.file just contains a traceback referring to a ValueError.

Any ideas? Thanks!

Was it helpful?

Solution

I believe the issue is in your serializer class where you define the image model field as Field. The generic Field is read-only, so that may be the source of the problem. Try simply removing that from your serializer, as it isn't necessary:

class PhotoSerializer(serializers.ModelSerializer):

    class Meta:
        model = Photo

Hope this helps, let me know how you get along.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top