Django DRF 添加 request.user 到 modelserializer

Django DRF add request.user to modelserializer

我正在使用 django rest 框架,我有一个通过 modelviewset 和 modelserializer 创建的对象。此视图只能由经过身份验证的用户访问,对象应将其 'uploaded_by' 字段设置为该用户。

我已经阅读了文档,得出的结论是这应该有效

视图集:

class FooViewset(viewsets.ModelViewSet):
    permission_classes = [permissions.IsAdminUser]
    queryset = Foo.objects.all()
    serializer_class = FooSerializer

    def get_serializer_context(self):
        return {"request": self.request}

序列化器:

class FooSerializer(serializers.ModelSerializer):
    uploaded_by = serializers.PrimaryKeyRelatedField(
        read_only=True, default=serializers.CurrentUserDefault()
    )

    class Meta:
        model = Foo
        fields = "__all__"

但是,这会导致以下错误:

django.db.utils.IntegrityError: NOT NULL constraint failed: bar_foo.uploaded_by_id

这表明 "uploaded_by" 没有被序列化程序填充。

根据我对文档的理解,这应该将字段添加到序列化程序的验证数据中,作为创建方法的一部分。

显然我误会了什么!

问题在于您的 uploaded_by 字段的 read_only 属性:

Read-only fields are included in the API output, but should not be included in the input during create or update operations. Any 'read_only' fields that are incorrectly included in the serializer input will be ignored.

Set this to True to ensure that the field is used when serializing a representation, but is not used when creating or updating an instance during deserialization.

Source

基本上它用于显示对象的表示,但不包括在任何更新和创建过程中。

相反,您可以覆盖 create 函数以通过手动分配来存储所需的用户。

class FooSerializer(serializers.ModelSerializer):

    uploaded_by = serializers.PrimaryKeyRelatedField(read_only=True)

    def create(self, validated_data):
        foo = Foo.objects.create(
            uploaded_by=self.context['request'].user,
            **validated_data
        )
        return foo

DRF 教程 recommend 在这种情况下覆盖 perform_create 方法,然后编辑 serializer,使其反映到新字段

from rest_framework import generics, serializers
from .models import Post


class PostSerializer(serializers.HyperlinkedModelSerializer):
    author = serializers.ReadOnlyField(source='author.username')

    class Meta:
        model = models.Post
        fields = ['title', 'content', 'author']


class ListPost(generics.ListCreateAPIView):
    queryset = Post.objects.all()
    serializer_class = PostSerializer

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

更清洁的方式:

class PostCreateAPIView(CreateAPIView, GenericAPIView):
    queryset = Post.objects.all()
    serializer_class = PostCreationSerializer

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

class PostCreationSerializer(serializers.ModelSerializer):
    author = serializers.PrimaryKeyRelatedField(read_only=True)

    class Meta:
        model = Post
        fields = ("content", "author")