我有这个评级课程的代码,应该从请求授权和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')
。但是存在一个问题:只要该约束在代码中,没有user
或lesson
字段的请求会因field required
错误而被拒绝,即使它们是read_only
。
(如果我使用unique_together('user','lesson')
进行迁移,则删除它可以使用的那一行,但只要它在那里我就会收到错误。)
我想在那里保留一些代码,以免我在以后的迁移中意外删除unique_together
约束。
答案 0 :(得分:2)
这是一个特殊情况,需要采用不同的方法。以下是关于此案例的django-rest-framework
documentation(请参阅说明):
处理此问题的正确方法是明确指定字段 序列化程序,同时提供
read_only=True
和default=…
关键字参数。
在您的情况下,您需要在user
上明确定义lesson
和RatingSerializer
字段,如下所示:
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)
我希望这会有所帮助!