Django Rest Framework выдает IntegrityError. значение NULL в столбце «creator_id» нарушает ненулевое ограничение - PullRequest
0 голосов
/ 02 апреля 2020

Django Rest Framework продолжает выдавать ошибку целостности в / posts / с сообщением: null value in column "creator_id" violates not-null constraint. Не совсем уверен, что вызывает эту проблему. Из панели администратора я могу создать сообщение без проблем.

Вот моя модель сообщения. Пользователь является внешним ключом:

class Post(models.Model):
    """Post object"""

    creator = models.ForeignKey(get_user_model(), on_delete=models.CASCADE)
    title = models.CharField(max_length=255, null=False, blank=False)
    content = models.TextField(blank=True, null=True)
    audio_file = models.FileField(
        null=False, blank=False,
        upload_to='audio_directory',
        validators=[validate_file_extension, validate_file_size]
        )
    cover_image = models.ImageField(
        upload_to='images/post_covers',
        default='images/defaults/default_cover.png',
        blank=False,
        null=False
        )
    tags = models.ManyToManyField(Tag, blank=True)
    duration = models.CharField(
        max_length=6,
        blank=True,
        default=0,
        help_text='Length of post in minutes'
        )
    category = models.ForeignKey(Category, on_delete=models.CASCADE, blank=False)
    featured = models.BooleanField(u'Featured', default=False)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    objects = models.Manager()
    sorted_objects = PostQuerySet.as_manager()


    class Meta:
        verbose_name = _('post')
        verbose_name_plural = _('post')
        ordering = ('-featured', '-created_at',)

    def __str__(self):
        return self.title

    @property
    def is_featured(self):
        return self.featured

В представлении thePost используется ModelViewSet, как показано в приведенном ниже коде:

class PostViewSet(viewsets.ModelViewSet):
    serializer_class = PostSerializer
    search_fields = (['title', 'creator', 'category'])

    def get_queryset(self):
        sorting = self.request.query_params.get('sorting', None)
        if sorting == 'newest':
            return Post.sorted_objects.newest()
        if sorting == 'trending':
            return Post.sorted_objects.likes_last_week()
        return Post.sorted_objects.likes()

    def get_permissions(self):
        return (permissions.IsAuthenticated(),)

    @method_decorator(cache_page(60))
    def dispatch(self, *args, **kwargs):
        return super(PostViewSet, self).dispatch(*args, **kwargs)

    @action(methods=['post'], permission_classes=[permissions.IsAuthenticated], detail=True)
    def like(self, request, pk=None):
        if request.data.get('point') is None:
            return Response({
                'status': 'Not Found',
                'message': 'point field does not exist in request body.'
            }, status=status.HTTP_400_BAD_REQUEST)
        serializer = PostLikeSerializer(
            data={'post': pk, 'point': request.data['point']},
            context={'request': request}
            )
        if serializer.is_valid():
            serializer.save()
            post = Post.objects.get(pk=pk)
            return Response(PostSerializer(post, context={'request': request}).data)
        else:
            return Response(serializer.errors,
                            status=status.HTTP_400_BAD_REQUEST)

    @action(methods=['post'], permission_classes=[permissions.IsAuthenticated], detail=True)
    def cancel_like(self, request, pk=None):
        try:
            post = post.objects.get(pk=pk)
            instance = PostLike.objects.get(post=post, user=self.request.user)
            self.perform_destroy(instance)
            return Response(PostSerializer(post, context={'request': request}).data)
        except ObjectDoesNotExist:
            return Response({
                'status': 'Not Found',
                'message': 'Like does not exist.'
            }, status=status.HTTP_404_NOT_FOUND)

Вот сериализатор, в котором для создателя установлено значение read_only:

class PostSerializer(serializers.ModelSerializer):
    creator = UserSerializer(default=serializers.CurrentUserDefault(), read_only=True)
    audio_file = serializers.FileField(max_length=None, use_url=True)
    cover_image = serializers.ImageField(max_length=None, use_url=True)
    tags = serializers.PrimaryKeyRelatedField(many=True, queryset=Tag.objects.all())
    # category = CategorySerializer()

    class Meta:
        model = Post
        fields = (
            'id',
            'creator',
            'title',
            'content',
            'audio_file',
            'cover_image',
            'tags',
            'duration',
            'category',
            'featured',
            'created_at',
            'updated_at'
            )
        read_only_fields = ('id', 'created_at', 'updated_at', 'like_count',)

    def to_representation(self, obj):
        return_obj = super(PostSerializer, self).to_representation(obj)
        is_liked_me = False
        is_creator_me = False
        if isinstance(self.context['request'].user, get_user_model()):
            is_liked_me = obj.postlike_set.filter(
                                user=self.context['request'].user).exists()
            is_creator_me = obj.creator == self.context['request'].user
        new_obj = {
            'is_creator_me': is_creator_me,
            'is_liked_me': is_liked_me,
        }
        return_obj.update(new_obj)
        return return_obj

Каждый раз, когда я создаю сообщение на localhost: 8000 / posts /, я получаю сообщение об ошибке: null value in column "creator_id" violates not-null constraint

Вот абстрактная модель пользователя:

class AbstractUser(AbstractBaseUser, PermissionsMixin):
    email = models.EmailField(_('email address'), max_length=255, unique=True)

    username = models.CharField(
        _("Username"),
        unique=True,
        max_length=255,
        help_text=_(
            "Required. 255 characters or fewer. Letters, numbers and \
            @/./+/-/_ characters"),
        validators=[
            validators.RegexValidator(
                re.compile(r"^[\w.@+-]+$"),
                _("Enter a valid username."),
                _("invalid")
            )
        ]
    )

    bio = models.TextField(blank=True, null=True)
    website = models.CharField(verbose_name="Website", max_length=120, blank=True, null=True)

    is_staff = models.BooleanField(_('staff status'), default=False,
        help_text=_('Designates whether the user can log into this admin '
                    'site.'))
    is_active = models.BooleanField(_('active'), default=True,
        help_text=_('Designates whether this user should be treated as '
                    'active. Unselect this instead of deleting accounts.'))
    date_joined = models.DateTimeField(_('date joined'), default=timezone.now)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    objects = UserManager()

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = ['username']

    class Meta:
        verbose_name = _('User')
        verbose_name_plural = _('Users')
        abstract = True
        ordering = ['email']


    def get_short_name(self):
        return self.email

Пожалуйста, дайте мне знать, что я делаю не так здесь.

1 Ответ

1 голос
/ 02 апреля 2020

Вы установили creator поле как read_only=True. Таким образом, DRF не примет входное значение во время создания объекта . Вы можете прикрепить значение поля creator, переопределив метод perform_create(...) для PostViewSet

#serializers.py
class PostSerializer(serializers.ModelSerializer):
    <b>creator = UserSerializer(read_only=True)</b>
    # other code


#views.py
class PostViewSet(viewsets.ModelViewSet):
    # other code
    <b>def perform_create(self, serializer):
        serializer.save(creator=self.request.user)</b>
...