I thought my problem was https://github.com/encode/django-rest-framework/issues/937 which should have been fixed by https://github.com/encode/django-rest-framework/pull/1003 but it appears, whether I send in None or empty string, DRF isn't happy.
I'm using Django 1.11.6 and DRF 3.7.7
class Part(models.Model):
image = models.ImageField(null=True, blank=True)
class PartSerializer(serializers.ModelSerializer):
class Meta:
model = Part
fields = ('id', 'image')
class PartDetail(generics.RetrieveUpdateAPIView):
queryset = Part.objects.all()
serializer_class = PartSerializer
parser_classes = (MultiPartParser, FormParser)
# put image, works fine
with tempfile.NamedTemporaryFile(suffix='.jpg') as fp:
image = Image.new('RGB', (100, 200))
image.save(fp)
fp.seek(0)
data = {'image': fp}
self.client.put('/path/to/endpoint', data, format='multipart')
# clear image, attempt #1
data = {'image': None}
self.client.put('/path/to/endpoint', data, format='multipart')
AssertionError: {'image': ['The submitted data was not a file. Check the encoding type on the form.']}
# clear image, attempt #2
data = {'image': ''}
self.client.put('/path/to/endpoint', data, format='multipart')
AssertionError: <ImageFieldFile: None> is not None
You have to specify the image field explicitly to allow it to be null.
use this:
class PartSerializer(serializers.ModelSerializer):
image = serializers.ImageField(max_length=None, allow_empty_file=True, allow_null=True, required=False)
class Meta:
model = Part
fields = ('id', 'image')
check docs for more details.
I ran into something like this trying to write an Angular app that contacts a Django system through Django REST framework. DRF automatically generates forms for updating objects. If there's a FileField on an object and you don't upload a file into the update form when you submit it, the framework can automatically remove a previously uploaded file and leave the object with no file at all. The object's field is then null. I wanted my app to have this capability, that is, objects can have an attached file, but it isn't required, and a file can be attached and later removed. I tried to accomplish the removal by constructing a FormData object and sending it as a PUT request, but I couldn't figure out exactly what value to specify for the file field to make DRF delete the previously uploaded file, like what happens in DRF's automatically generated forms.
These didn't work:
let fd = new FormData();
fd.set('my_file', null); // TypeScript wouldn't let me do this
fd.set('my_file', ''); // Same error as your attempt #2
fd.set('my_file', new Blob([]); // Error about an empty file
What finally worked was
fd.set('my_file', new File([], ''));
which apparently means an empty file with no name. With that, I could send a PUT request that deletes the file attached to the object and leaves the resulting FileField null:
this.http.put<MyRecord>(url, fd);
where this.http is a an Angular HttpClient. I'm not sure how to construct such a PUT request in Python.
To leave the file in place, don't set anything for 'my_file' on the FormData.
On the Django side, I was using a subclass of ModelSerializer as the serializer, and the underlying FileField in the Model had options blank=True, null=True.
This is covered in the docs for FileField.delete
I would create an update method on your serializer that would clear the image using the ORM call
def update(self, instance, validated_data):
instance.part.delete(save = True)
or something similar.