Home > Software engineering >  Django Rest Framework Allow a request to set a foreign key Field in CreateAPIView
Django Rest Framework Allow a request to set a foreign key Field in CreateAPIView

Time:03-28

A thread belongs to a board. So I would like the ThreadList view to accept a POST request with the foreign key board. What I have attempted results in an error. AssertionError: Relational field must provide a queryset argument, override get_queryset, or set read_only=True

serializers.py

class ThreadSerializer(serializers.ModelSerializer):
 
    post = PostSerializer(many=True, read_only=True)
    # board = serializers.ReadOnlyField(source='board.id')
    board = serializers.PrimaryKeyRelatedField(source='board.id')

    class Meta:
        model = Thread
        fields = ['id', 'title', 'post', 'board']

views.py

class ThreadList(generics.ListCreateAPIView):

    permission_classes = [permissions.IsAuthenticatedOrReadOnly]
    def perform_create(self, serializer):
        serializer.save(thread_admin=self.request.user)

    queryset = Thread.objects.all()
    serializer_class = ThreadSerializer

models.py

class Board(models.Model):

    name = models.CharField(max_length=25, unique=True)
    created = models.DateTimeField(auto_now_add=True)
    board_admin = models.ForeignKey('auth.User', on_delete=models.CASCADE, related_name='board_admin')
    board_moderator = models.ManyToManyField(User, related_name='board_moderator')

    class Meta:
        ordering = ['created']


class Thread(models.Model):

    title = models.CharField(max_length=250)
    created = models.DateTimeField(auto_now_add=True)
    thread_admin = models.ForeignKey('auth.User', on_delete=models.CASCADE, related_name='thread')
    board = models.ForeignKey(Board, on_delete=models.CASCADE, related_name="thread")

    class Meta:
        ordering = ['created']

CodePudding user response:

serializers.PrimaryKeyRelatedField has a required argument queryset that needs to include to tell what id of which queryset needs to be validated against.

In your case, it should be

class ThreadSerializer(serializers.ModelSerializer):
    ...
    board = serializers.PrimaryKeyRelatedField(queryset=Board.objects.all())
    ...

Notes

Notice that you don't need to specify source='board.id' since django-rest-framework already handles that for you.

Extra

If there's no extra parameters that will be pass into serializers.PrimaryKeyRelatedField to change the default behavior, you can just include board in class Meta's fields and no need to use serializers.PrimaryKeyRelatedField manually.

class ThreadSerializer(serializers.ModelSerializer):
    post = PostSerializer(many=True, read_only=True)

    class Meta:
        model = Thread
        fields = ['id', 'title', 'post', 'board']
  • Related