unique_together两个字段混乱与read_only_fields

时间:2016-03-30 19:09:48

标签: python django django-rest-framework

我有这个评级课程的代码,应该从请求授权和URL自动添加用户和课程:

#views.py

class RatingViewSet(
    mixins.ListModelMixin,
    mixins.CreateModelMixin,
    viewsets.GenericViewSet
):
    permission_classes = [permissions.IsAuthenticated]
    serializer_class = RatingSerializer

    def perform_create(self, serializer):
        lessonInstance = Lesson.objects.get(id = self.kwargs['lessonID'])
        serializer.save(user=self.request.user, lesson = lessonInstance)
    def get_queryset(self):
        lessonID = self.kwargs['lessonID']
        return Rating.objects.filter(user=self.request.user, lesson=lessonID)

#serializers.py

class RatingSerializer(serializers.ModelSerializer):
    class Meta:
        model = Rating
        fields = ('id', 'lesson','user', 'difficulty')
        read_only_fields = ('id', 'user','lesson')

#models.py

class Rating(models.Model):
    user = models.ForeignKey(settings.AUTH_USER_MODEL)
    lesson = models.ForeignKey('lessons.Lesson')
    difficulty = models.IntegerField()
    class meta:
        unique_together('user','lesson')

我希望每个用户/课程获得最多1个评分,因此unique_together('user','lesson')。但是存在一个问题:只要该约束在代码中,没有userlesson字段的请求会因field required错误而被拒绝,即使它们是read_only

(如果我使用unique_together('user','lesson')进行迁移,则删除它可以使用的那一行,但只要它在那里我就会收到错误。)

我想在那里保留一些代码,以免我在以后的迁移中意外删除unique_together约束。

2 个答案:

答案 0 :(得分:2)

这是一个特殊情况,需要采用不同的方法。以下是关于此案例的django-rest-framework documentation(请参阅说明):

  

处理此问题的正确方法是明确指定字段   序列化程序,同时提供read_only=Truedefault=…   关键字参数。

在您的情况下,您需要在user上明确定义lessonRatingSerializer字段,如下所示:

class RatingSerializer(serializers.ModelSerializer):
    user = serializers.PrimaryKeyRelatedField(read_only=True, default=serializers.CurrentUserDefault())  # gets the user from request
    lesson = serializers.PrimaryKeyRelatedField(read_only=True, default=None)  # or any other appropriate value

    class Meta:
        model = Rating
        fields = ('id', 'lesson','user', 'difficulty')
祝你好运!

答案 1 :(得分:0)

如果某个字段为read_only=True,则validated_data将忽略该字段的数据=>原因error required field,请访问doc

我也在类似的情况下遇到了这个问题,然后尝试了@iulian的回答,但是没有运气! 不再支持此组合read_only + default的行为,请检查this

我通过2种解决方案解决了这个问题:

  • 我的模特:
class Friendship(TimeStampedModel):
    """Model present Friendship request"""
    from_user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='friendship_from_user')
    to_user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='friendship_to_user')

    class Meta:
        unique_together = ('from_user', 'to_user')

解决方案1. 编写自己的CurrentUserDefault类以获取用户ID,然后将其设置为序列化程序的默认属性数据(引自#51940976

class CurrentUserDefault(object):
    def set_context(self, serializer_field):
        self.user_id = serializer_field.context['request'].user.id

    def __call__(self):
        return self.user_id

class FriendshipSerializer(serializers.ModelSerializer):
    from_user_id = serializers.HiddenField(default=CurrentUserDefault())

    class Meta:
        model = Friendship
        fields = ('id', 'from_user', 'from_user_id', 'to_user', 'status')
        extra_kwargs = {
            'from_user': {'read_only': True},
        }

解决方案2。覆盖序列化程序的创建方法以为用户ID设置数据(引自this

class FriendshipSerializer(serializers.ModelSerializer):
    class Meta:
        model = Friendship
        fields = ('id', 'from_user', 'to_user', 'status')
        extra_kwargs = {
            'from_user': {'read_only': True},
        }


    def create(self, validated_data):
        """Override create to provide a user via request.user by default.

        This is require since the read_only `user` filed is not included by default anymore since
        https://github.com/encode/django-rest-framework/pull/5886.
        """
        if 'user' not in validated_data:
            validated_data['from_user'] = self.context['request'].user

        return super(FriendshipSerializer, self).create(validated_data)

我希望这会有所帮助!