Search code examples
pythondjangodjango-rest-frameworknotnull

rest_framework NOT NULL constraint failed: tasks_tasks.assigner_id


I am making an app where assigner can assign tasks to assignee when i run the server and try to add a task i get this error:

NOT NULL constraint failed: tasks_tasks.assigner_id

here is my views:

from rest_framework import viewsets, permissions
from .models import Tasks
from .serializers import TasksSerializer, UserSerializer
from django.contrib.auth.models import User


class UserViewSet(viewsets.ReadOnlyModelViewSet):
    queryset = User.objects.all()
    serializer_class = UserSerializer


class TasksViewSet(viewsets.ModelViewSet):
    queryset = Tasks.objects.all()
    serializer_class = TasksSerializer
    permission_classes = (permissions.IsAuthenticatedOrReadOnly,)

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

here is my serializers.py

from rest_framework import serializers
from .models import Tasks
from django.contrib.auth.models import User


class TasksSerializer(serializers.ModelSerializer):
    assigner = serializers.ReadOnlyField(source='assigner.username')

    class Meta:
        model = Tasks
        fields = ('id', 'url', 'title', 'description', 'assigner', 'assignee')


class UserSerializer(serializers.ModelSerializer):
    tasks = serializers.HyperlinkedIdentityField(many=True, view_name='tasks_details', read_only=True)

    class Meta:
        model = User
        fields = ('id', 'url', 'username', 'tasks')

and finally my models.py:

from django.db import models

class Tasks(models.Model):
    created = models.DateTimeField(auto_now_add=True)
    title = models.CharField(max_length=100)
    description = models.TextField()
    assigner = models.ForeignKey('auth.User', related_name='tasks', on_delete=models.CASCADE)
    assignee = models.ForeignKey('auth.User', related_name='assigned', on_delete=models.CASCADE)

    class Meta:
        ordering = ('created',)

Solution

  • You've made assigner a read only field with source assigner.username -this is your problem. I think you could get around this by defining two fields instead, one read_only and one write_only:

    class TasksSerializer(serializers.ModelSerializer):
    assigner_name = serializers.ReadOnlyField(source='assigner.username')
    assigner = serializers.PrimaryKeyRelatedField(write_only=True, queryset=User.objects.all(), required=True)
    class Meta:
        model = Tasks
        fields = ('id', 'url', 'title', 'description', 'assigner', 'assignee', 'assigner_name')
    

    The effect of this code is that when your serializer is 'writing' (de-serializing) it will accept the assigner id which you pass into the save method as the keyword argument assigner. When it then serializes the task to json, it will look for the assigner.name and return it under the key assigner_name and miss out assigner.

    In the view, you'd then pass in the primary key (rather than the whole object) to the serializer save method:

    serializer.save(assigner=self.request.user.pk)