我有以下代码完美运行。我可以通过选择图像和用户从DRF面板创建Post
对象。但是我希望DRF由当前登录的用户填充用户字段。
models.py
class Post(TimeStamped):
user = models.ForeignKey(User)
photo = models.ImageField(upload_to='upload/')
hidden = models.BooleanField(default=False)
upvotes = models.PositiveIntegerField(default=0)
downvotes = models.PositiveIntegerField(default=0)
comments = models.PositiveIntegerField(default=0)
serializers.py
class PostSerializer(serializers.ModelSerializer):
class Meta:
model = Post
fields = ['id', 'user', 'photo']
views.py
class PhotoListAPIView(generics.ListCreateAPIView):
queryset = Post.objects.filter(hidden=False)
serializer_class = PostSerializer
authentication_classes = (SessionAuthentication, BasicAuthentication)
permission_classes = (IsAuthenticated,)
我该怎么做?
答案 0 :(得分:52)
您可以使用CurrentUserDefault:
user = serializers.PrimaryKeyRelatedField(
read_only=True,
default=serializers.CurrentUserDefault()
)
请参阅http://www.django-rest-framework.org/api-guide/validators/#currentuserdefault
答案 1 :(得分:41)
在我的头顶,你可以覆盖perform_create()
方法:
class PhotoListAPIView(generics.ListCreateAPIView):
...
def perform_create(self, serializer):
serializer.save(user=self.request.user)
给出一个镜头并让我知道它是否有效
答案 2 :(得分:13)
这取决于您的使用案例。如果你希望它是"只写",意味着DRF会在写入时自动填充字段并且不会返回读取,那么最直接的实现according to the docs将与一个HiddenField:
class PhotoListAPIView(generics.ListCreateAPIView):
user = serializers.HiddenField(
default=serializers.CurrentUserDefault(),
)
如果您希望它是可读的,您可以使用PrimaryKeyRelatedField,同时注意序列化程序在写入时预填充字段 - 否则用户可以将user
字段设置为指向其他随机用户。
class PhotoListAPIView(generics.ListCreateAPIView):
user = serializers.PrimaryKeyRelatedField(
# set it to read_only as we're handling the writing part ourselves
read_only=True,
)
def perform_create(self, serializer):
serializer.save(user=self.request.user)
最后请注意,如果您使用的是更详细APIView
而不是generics.ListCreateAPIView
,则必须覆盖create
而不是perform_create
,如下所示:< / p>
class PhotoListAPIView(generics.ListCreateAPIView):
user = serializers.PrimaryKeyRelatedField(
read_only=True,
)
def create(self, validated_data):
# add the current User to the validated_data dict and call
# the super method which basically only creates a model
# instance with that data
validated_data['user'] = self.request.user
return super(PhotoListAPIView, self).create(validated_data)
答案 3 :(得分:4)
@ DaveBensonPhillips的答案可能会在你的特定情况下使用一段时间,但它不是非常通用的,因为它打破了OOP继承链。
ListCreateAPIView
继承自CreateModelMixin
已saves序列化程序。除非你有充分的理由不这样做,否则你应该总是努力获得完整的重写方法链。通过这种方式,您的代码可以保持DRY并且可以抵御更改:
class PhotoListAPIView(generics.ListCreateAPIView):
...
def perform_create(self, serializer):
serializer.validated_data['user'] = self.request.user
return super(PhotoListAPIView, self).perform_create(serializer)
答案 4 :(得分:2)
您必须覆盖generics.ListCreateAPIView
创建对象的默认行为。
class PhotoListAPIView(generics.ListCreateAPIView):
queryset = Post.objects.filter(hidden=False)
authentication_classes = (SessionAuthentication, BasicAuthentication)
permission_classes = (IsAuthenticated,)
def get_serializer_class(self):
if self.request.method == 'POST':
return CreatePostSerializer
else:
return ListPostSerializer
def create(self, request, *args, **kwargs):
# Copy parsed content from HTTP request
data = request.data.copy()
# Add id of currently logged user
data['user'] = request.user.id
# Default behavior but pass our modified data instead
serializer = self.get_serializer(data=data)
serializer.is_valid(raise_exception=True)
self.perform_create(serializer)
headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
.get_serializer_class()
没有必要,因为您可以指定哪些字段是只读序列化程序的,但根据我所处理的项目,我通常最终得到'非对称'序列化程序,即取决于不同的序列化程序关于预期的行动。
答案 5 :(得分:2)
您可以避免在请求中传递user
,并且不会在输出中看到它,但是DRF会自动填充它:
from rest_framework import serializers
class MyModelSerializer(serializers.ModelSerializer):
user = serializers.HiddenField(default=serializers.CurrentUserDefault())
class Meta:
model = models.MyModel
fields = (
'user',
'other',
'fields',
)
答案 6 :(得分:1)
def post(self, request, format=None)
serializer = ProjectSerializer(data=request.data)
request.data['user'] = request.user.id
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST
答案 7 :(得分:0)
这是在serializers.py中对我有用的地方,在这里我也使用嵌套数据。我想显示created_by_username而不必查找其他用户。
class ListSerializer(serializers.ModelSerializer):
"""
A list may be created with items
"""
items = ItemSerializer(many=True)
# automatically set created_by_id as the current user's id
created_by_id = serializers.PrimaryKeyRelatedField(
read_only=True,
)
created_by_username = serializers.PrimaryKeyRelatedField(
read_only=True
)
class Meta:
model = List
fields = ('id', 'name', 'description', 'is_public',
'slug', 'created_by_id', 'created_by_username', 'created_at',
'modified_by', 'modified_at', 'items')
def create(self, validated_data):
items_data = validated_data.pop('items', None)
validated_data['created_by_id'] = self.context['request'].user
validated_data['created_by_username'] = self.context['request'].user.username
newlist = List.objects.create(**validated_data)
for item_data in items_data:
Item.objects.create(list=newlist, **item_data)
return newlist
答案 8 :(得分:0)
从DRF version 3.8.0(Pull Request discussion)开始,您可以在序列化程序中覆盖save()。
from rest_framework import serializers
...
class PostSerializer(serializers.ModelSerializer):
user = serializers.PrimaryKeyRelatedField(read_only=True, default=serializers.CurrentUserDefault())
class Meta:
model = Post
fields = ['id', 'user', 'photo']
def save(self, **kwargs):
"""Include default for read_only `user` field"""
kwargs["user"] = self.fields["user"].get_default()
return super().save(**kwargs)