I am using django rest framework, and I have an object being created via a modelviewset, and a modelserializer. This view is only accessible by authenticated users, and the object should set its 'uploaded_by' field, to be that user.
I've read the docs, and come to the conclusion that this should work
viewset:
class FooViewset(viewsets.ModelViewSet):
permission_classes = [permissions.IsAdminUser]
queryset = Foo.objects.all()
serializer_class = FooSerializer
def get_serializer_context(self):
return {"request": self.request}
serializer:
class FooSerializer(serializers.ModelSerializer):
uploaded_by = serializers.PrimaryKeyRelatedField(
read_only=True, default=serializers.CurrentUserDefault()
)
class Meta:
model = Foo
fields = "__all__"
However, this results in the following error:
django.db.utils.IntegrityError: NOT NULL constraint failed: bar_foo.uploaded_by_id
Which suggests that "uploaded_by" is not being filled by the serializer.
Based on my understanding of the docs, this should have added the field to the validated data from the serializer, as part of the create method.
Clearly I've misunderstood something!
The problem lies in the read_only
attribute on your uploaded_by
field:
Read-only fields are included in the API output, but should not be included in the input during create or update operations. Any 'read_only' fields that are incorrectly included in the serializer input will be ignored.
Set this to True to ensure that the field is used when serializing a representation, but is not used when creating or updating an instance during deserialization.
Source
Basically it's used for showing representation of an object, but is excluded in any update and create-process.
Instead, you can override the create
function to store the desired user by manually assigning it.
class FooSerializer(serializers.ModelSerializer):
uploaded_by = serializers.PrimaryKeyRelatedField(read_only=True)
def create(self, validated_data):
foo = Foo.objects.create(
uploaded_by=self.context['request'].user,
**validated_data
)
return foo
DRF tutorial recommend to override perform_create
method in this case and then edit serializer
so, that it reflect to new field
from rest_framework import generics, serializers
from .models import Post
class PostSerializer(serializers.HyperlinkedModelSerializer):
author = serializers.ReadOnlyField(source='author.username')
class Meta:
model = models.Post
fields = ['title', 'content', 'author']
class ListPost(generics.ListCreateAPIView):
queryset = Post.objects.all()
serializer_class = PostSerializer
def perform_create(self, serializer):
return serializer.save(author=self.request.user)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With