Reputation: 22747
This is my ViewSet:
class PostViewSet(viewsets.ModelViewSet):
queryset = Post.objects.all()
serializer_class = PostSerializer
permission_classes = (IsAuthenticated, IsLikeOrOwnerDeleteOrReadOnly,)
def perform_create(self, serializer):
# Passing location to the serializer.
serializer.save(owner=self.request.user, location=self.request.user.userextended.location)
And this is my serializer:
class PostSerializer(serializers.ModelSerializer):
class Meta:
model = Post
fields = ('id', 'owner', 'post', 'page', 'location')
read_only_fields = ('id', 'owner', 'location')
def create(self, validated_data):
post = Post(
owner = validated_data['owner'],
post = validated_data['post'],
location = validated_data['location'],
)
if validated_data.get('page', None):
post.page = validated_data['page']
post.save()
return post
def validate(self, data):
if not data.get('page', None):
return data
# The KeyError being raised points to the line below.
if data['location'] == data['page']:
return data
raise serializers.ValidationError('Error.')
The problem is, even though I am passing locaiton
to the serializer from my perform_create()
method, I get an error raised when I try to create a post. The error is:
if data['location'] == data['page']:
KeyError: 'location'
I'm assuming that DRF does the serializer validation check before executing the perform_create()
method? If yes, how do I accomplish what I need to? (i.e. how do I check if data['location'] == data['page']
when location
is passed from my view to the serializer and page
is from my serializer?).
Upvotes: 2
Views: 1896
Reputation: 22697
According to DRF docs.
Sometimes you'll want your view code to be able to inject additional data at the point of saving the instance. This additional data might include information like the current user, the current time, or anything else that is not part of the request data.
You can do so by including additional keyword arguments when calling .save()
serializer.save(owner=request.user)
Any additional keyword arguments will be included in the validated_data argument when .create() or .update() are called.
So, you can access to extra keyword arguments only within create()
or update()
method, not in validate()
Said that, how can you pass extra data to your serializer ? use context serializer
Override get_serializer_context
method in your view
class PostViewSet(viewsets.ModelViewSet):
queryset = Post.objects.all()
serializer_class = PostSerializer
permission_classes = (IsAuthenticated, IsLikeOrOwnerDeleteOrReadOnly,)
get_serializer_context(self):
return {'location':self.request.user.userextended.location}
Then in your validate serializer method
def validate(self, data):
if not data.get('page', None):
return data
location = self.context.get('location')
if location == data['page']:
return data
raise serializers.ValidationError('Error.')
Upvotes: 3