Home > Mobile >  How to make a field the same as int:pk in django rest framework?
How to make a field the same as int:pk in django rest framework?

Time:02-03

I have a serializer

class AnswerQuestionsSerializer(serializers.ModelSerializer):
    user = serializers.PrimaryKeyRelatedField(read_only=True, default=serializers.CurrentUserDefault())

    class Meta:
        model = Answer
        fields = ('answer', 'user', 'question', 'number_of_points', 'moderate_status',)

And the view

class AnswerQuestions(generics.CreateAPIView, generics.GenericAPIView):
    queryset = Answer.objects.all()
    serializer_class = AnswerQuestionsSerializer

    def perform_create(self, serializer):
        return serializer.save(user=self.request.user)

    def get_queryset(self):
        return super().get_queryset().filter(
            question_id=self.kwargs['pk']
        )

The model looks like this

    answer = models.TextField()
    created_at = models.DateTimeField(editable=False, default=timezone.now)
    updated_at = models.DateTimeField(default=timezone.now)
    user = models.ForeignKey('users.CustomUser', on_delete=models.PROTECT)
    question = models.ForeignKey('Question', on_delete=models.PROTECT)
    number_of_points = models.IntegerField(default=0)
    moderate_status = models.BooleanField(default=False)

url

path('answerQuestions/<int:pk>', AnswerQuestions.as_view()),

And i set the url to answerQuestions/int:pk, so when i use post request lets say answerQuestions/3 i still need to put "question": "3" in body because it won't read it automatically. Do you have any idea how to make it automatically hit the question of the id provided in the url? Which in this case would be 3.

Internal Server Error: /api/v1/answerQuestions/3
Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/django/core/handlers/exception.py", line 47, in inner
    response = get_response(request)
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/django/core/handlers/base.py", line 179, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view
    return view_func(*args, **kwargs)
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/django/views/generic/base.py", line 70, in view
    return self.dispatch(request, *args, **kwargs)
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/rest_framework/views.py", line 509, in dispatch
    response = self.handle_exception(exc)
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/rest_framework/views.py", line 469, in handle_exception
    self.raise_uncaught_exception(exc)
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/rest_framework/views.py", line 480, in raise_uncaught_exception
    raise exc
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/rest_framework/views.py", line 506, in dispatch
    response = handler(request, *args, **kwargs)
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/rest_framework/generics.py", line 190, in post
    return self.create(request, *args, **kwargs)
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/rest_framework/mixins.py", line 19, in create
    self.perform_create(serializer)
  File "/Users/jakubstrawa/programming/gitlabdeor/api/questions/views.py", line 16, in perform_create
    return serializer.create(**self.perform_create_kwargs())
TypeError: create() got an unexpected keyword argument 'user'

CodePudding user response:

You can mark the question as a read_only=True field:

class AnswerQuestionsSerializer(serializers.ModelSerializer):
    user = serializers.PrimaryKeyRelatedField(read_only=True, default=serializers.CurrentUserDefault())
    question = serializers.PrimaryKeyRelatedField(read_only=True)

    class Meta:
        model = Answer
        fields = ('answer', 'user', 'question', 'number_of_points', 'moderate_status',)

and in the view inject it in the create method of the serializer:

class AnswerQuestions(generics.CreateAPIView, generics.GenericAPIView):
    queryset = Answer.objects.all()
    serializer_class = AnswerQuestionsSerializer

    def perform_create(self, serializer):
        return serializer.save(user=self.request.user, question_id=self.kwargs['pk'])

    def get_queryset(self):
        return super().get_queryset().filter(
            question_id=self.kwargs['pk']
        )

You could work with a mixin, something like:

class ParentKeyAPIView:
    parent_url_pk = 'pk'
    parent_model_field = None

    def perform_create_kwargs(self, **kwargs):
        kwargs[self.parent_model_field] = self.kwargs[self.parent_url_pk]
        return kwargs

    def perform_create(self, serializer):
        return serializer.save(**self.perform_create_kwargs())

    def get_queryset(self):
        return super().get_queryset().filter(
            **{self.parent_model_field: self.kwargs[self.parent_url_pk]}
        )

Then you can use such mixin as:

class AnswerQuestions(ParentKeyAPIView, generics.CreateAPIView):
    model = Answer
    parent_model_field = 'question_id'
    serializer_class = AnswerQuestionsSerializer

    def perform_create_kwargs(self, **kwargs):
        return super().perform_create_kwargs(user=self.request.user, **kwargs)

Then the mixin will at least take care both of the filtering and the creation of the object.

  •  Tags:  
  • Related