I have a requirement which I would like to allow multiple files to be uploaded within the same post request to create an object. I currently have a method of doing this, but after looking at some other examples it doesn't appear to be intended way to do it.
models.py
class Analyzer(models.Model):
name = models.CharField(max_length=100, editable=False, unique=True)
class Atomic(models.Model):
name = models.CharField(max_length=20, unique=True)
class Submission(models.Model):
class Meta:
ordering = ['-updated_at']
issued_at = models.DateTimeField(auto_now_add=True, editable=False)
completed = models.BooleanField(default=False)
analyzers = models.ManyToManyField(Analyzer, related_name='submissions')
atomic = models.ForeignKey(Atomic, verbose_name='Atomic datatype', related_name='submission', on_delete=models.CASCADE)
class BinaryFile(models.Model):
class Meta:
verbose_name = 'Binary file'
verbose_name_plural = 'Binary files'
def __str__(self):
return self.file.name
submission = models.ForeignKey(Submission, on_delete=models.CASCADE, related_name='binary_files')
file = models.FileField(upload_to='uploads/binary/')
serializers.py
class BinaryFileSerializer(serializers.ModelSerializer):
class Meta:
model = models.BinaryFile
fields = '__all__'
class SubmissionCreateSerializer(serializers.ModelSerializer):
class Meta:
model = models.Submission
fields = ['id', 'completed', 'atomic', 'analyzers', 'binary_files']
id = serializers.ReadOnlyField()
completed = serializers.ReadOnlyField()
atomic = serializers.PrimaryKeyRelatedField(many=False, queryset=models.Atomic.objects.all()
analyzers = serializers.PrimaryKeyRelatedField(many=True, queryset=models.Analyzer.objects.all()
binary_files = BinaryFileSerializer(required=True, many=True)
def validate(self, data):
# # I dont really like manually taking invalidated input!!
data['binary_files'] = self.initial_data.getlist('binary_files')
return data
def create(self, validated_data):
submission = models.Submission.objects.create(
atomic=validated_data['atomic']
)
submission.analyzers.set(validated_data['analyzers'])
# # Serialize the files - this seems too late to be doing this!
for file in validated_data['binary_files']:
binary_file = BinaryFileSerializer(
data={'file': file, 'submission': submission.id}
)
if binary_file.is_valid():
binary_file.save()
return submission
Main question: While the above works, the child serializer (BinaryFileSerializer) doesn't get called until I explicitly call it in create(), which is after the validation should have occurred. Why does this never get called?
I also don't like the fact I have to manually do a self.initial_data.getlist('binary_files')
and manually add it to data
- this should have already been added and validated, no?
My thought is that as I defined binary_files = BinaryFileSerializer
, this serializer should be called to validate that particular fields input?
FYI, I'm using the following to test POST uploads:
curl -F "binary_files=@file2.txt" -F "binary_files=@file2.txt" -F "atomic=7" -F "analyzers=12" -H "Accept: application/json; indent=4" http://127.0.0.1:8000/api/submit/
TIA!
Update: The question is now, if a validate() funciton is added to the BinaryFileSerializer, why does it not get called?