Reputation: 6051
I'm trying to create an endpoint that accepts (key/value) data and multiple files. The user can send serial
and multiple files along with his request. Uploaded files must be saved in FileModel
and add a relation to the RequestModel
. The problem is when I send the request the RequestSerializer
can't resolve the files
and I get an error about missing the files
field.
#tests.py
def test_create_request_with_files(self):
with tempfile.NamedTemporaryFile() as file:
file.write(b"SomeFakeData")
file.seek(0)
request = {
'files': [file],
'serial': "SomeSerial",
}
res = self.client.post(
'/CreateRequest/', request, format='multipart')
print(res.data)
self.assertEqual(res.status_code, status.HTTP_201_CREATED)
#---------------------------------------------------------------------------
# models.py
class FileModel(models.Model):
file = models.FileField(upload_to='upload_files')
class RequestModel(models.Model):
serial = models.CharField(max_length=100)
files = models.ManyToManyField('FileModel', blank=True)
def __str__(self):
return str(self.id)
#---------------------------------------------------------------------------
# serializers.py
class FileSerializer(serializers.ModelSerializer):
class Meta:
model = FileModel
fields = '__all__'
read_only_fields = ('id',)
class RequestSerializer(serializers.ModelSerializer):
files = FileSerializer(many=True)
def create(self, validated_data):
files = validated_data.pop('files')
request_model = RequestModel.objects.create(**validated_data)
for file in files:
file_model = FileModel.objects.create(file=file)
request_model.files.add(file_model)
request_model.save()
return request_model
class Meta:
model = RequestModel
fields = '__all__'
read_only_fields = ('id')
#---------------------------------------------------------------------------
#views.py
class RequestList(generics.ListCreateAPIView):
queryset = RequestModel.objects.all()
serializer_class = RequestSerializer
parser_classes = (FormParser, MultiPartParser)
def post(self, request, *args, **kwargs):
serializer = RequestSerializer(data=request.data)
if serializer.is_valid():
request_model = serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
The output of test:
{'files': [ErrorDetail(string='This field is required.', code='required')]}
Fs
======================================================================
FAIL
----------------------------------------------------------------------
Traceback (most recent call last):
File ".tests.py", line 95, in test_create_request_with_files
self.assertEqual(res.status_code, status.HTTP_201_CREATED)
AssertionError: 400 != 201
Upvotes: 0
Views: 241
Reputation: 1553
This is not a problem with django. You cannot pass an object when you use multipart/form-data
. A list will be converted to [object Object]
string.
Instead try: file1
, file2
etc...
I would use a dynamic parser something like:
count = 1
files = []
f = request.data.get('file{}'.fomat(count))
while f is not None:
files.append(f)
count += 1
f = request.data.get('file{}'.fomat(count))
Upvotes: 1