Reputation: 41
I'm using DRF to create an user with multiple attachments. When you create an user you have to upload one or more files. When I make an update of an user which you load a new file (no other modified field) the response back the old instance.
I solved by forcing the '_prefetched_objects_cache' attribute in the serializer before returning the instance.
setattr(instance, '_prefetched_objects_cache', True)
Is it correct? You have other solutions about it? thanks
There is my code
class User(models.Model):
#field of user model
class Attachment(models.Model):
class Meta:
db_table = 'attachment'
path = models.FileField()
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='attachments')
dt_created = models.DateTimeField(auto_now_add=True, verbose_name='Created')
class AttachmentSerializer(serializers.ModelSerializer):
class Meta:
model = Attachment
fields = '__all__'
class UserSerializer(serializers.ModelSerializer):
attachments = AttachmentSerializer(many=True, read_only=True)
def create(self, validated_data):
user = User.objects.create(**validated_data)
for file_item in self.initial_data.getlist('attachments'):
c = Attachment(path=file_item, user=user)
c.save()
return user
def update(self, instance, validated_data):
for item in validated_data:
if User._meta.get_field(item):
setattr(instance, item, validated_data[item])
c = Attachment(path=self.context['request'].FILES['attachments'], user=instance)
c.save()
instance.save()
setattr(instance, '_prefetched_objects_cache', True)
return instance
io = StringIO.StringIO()
io.write('foo')
file = InMemoryUploadedFile(io, None, 'foo.txt', 'text', io.len, None)
file.seek(0)
self.user['attachments'] = [file, file]
data = self.user
response = self.client.post(url, data, format='multipart')
file = InMemoryUploadedFile(io, None, 'foo2.txt', 'text', io.len, None)
file.seek(0)
#url = url of user detail for update
local_user['attachments'].extend(response.data['attachments'])
local_user['attachments'].append(file)
data = local_user
response = self.client.put(path=url, data=data, format='multipart')
Upvotes: 4
Views: 5158
Reputation: 2521
In case you use form for posting to DRF, you could use FormParser
along with MultiPartParser
if you're posting your data using forms
ex.
...
from rest_framework.parsers import MultiPartParser, FormParser
...
class UserView(APIView):
parser_classes = (FormParser, MultiPartParser)
def post(self, request):
...
Files will be available under request.data
or request.FILES
as InMemoryUploadedFile
instance.
You can proceed working with those in serializer or whatever fits better for you view logic.
Don't forget to set enctype
to multipart/form-data
in your form, otherwise files won't get parsed properly ex.
<form action="..." method="POST" enctype="multipart/form-data">
<input type="file" name="file-1" />
<input type="file" name="file-2" />
</form>
Upvotes: 1