ー PupSoZeyDe ー
ー PupSoZeyDe ー

Reputation: 1392

Django: NOT NULL constraint failed: appname_post.user_id

I have the following django rest framework serializer and view for a model Post, and the models defined for the app are as following.

Now I wanted to test the API, so tried to "create" a new post from the API page, but then I got an error IntegrityError at /api/posts/ NOT NULL constraint failed: appname_post.user_id.

So then I tried to debug and checked its request.data value, it says it only has title and content but not user_id, as I could expect from the error above.

But now I have no idea how to tell the API automatically relate the user_id field to request.user.id. Isn't not enough to just add the user_id = serializers.ReadOnlyField(source='user.id') line? I could do "retrieve", "update", "patch" etc but just cannot "post" (create).

Thanks for your help.


class DevPerm(permissions.BasePermission):
    def has_object_permission(self, request, view, obj):
        return True 

    def has_permission(self, request, view):
        return True

class PostSerializer(serializers.HyperlinkedModelSerializer):

    user_id = serializers.ReadOnlyField(source='user.id')

    class Meta:
        model = Post
        fields = ('url',
                  'id',
                  'title',
                  'content',
                  'created_at',
                  'voters',
                  'comments',
                  'user_id',
                  )
                  
        read_only_fields = (
            'id', 
            'created_at', 
            "voters", 
            "comments", 
            # "user_id",
            )

class PostViewSet(viewsets.ModelViewSet):
    queryset = Post.objects.all()
    serializer_class = PostSerializer
    permission_classes = [permissions.IsAuthenticated, DevPerm,]

class Post(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='posts', default="")
    created_at = models.DateTimeField(auto_now_add=True)
    
    title = models.TextField(blank=True)
    content = models.TextField(blank=True)
    
    voters = models.ManyToManyField(User, related_name='votes', default="")

class Comment(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='comments', default="")
    post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='comments', default="")
    created_at = models.DateTimeField(auto_now_add=True)

    content = models.TextField(blank=True)

Upvotes: 0

Views: 644

Answers (1)

Arjun Shahi
Arjun Shahi

Reputation: 7330

You can override perform_create method inside you ModelViewSet.

class PostViewSet(viewsets.ModelViewSet):
    queryset = Post.objects.all()
    serializer_class = PostSerializer
    permission_classes = [permissions.IsAuthenticated, DevPerm,]

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

Upvotes: 1

Related Questions