2016-02-20 60 views
19

我有以下代碼完美工作。通過選擇圖像和用戶,我可以從DRF面板創建一個Post對象。不過,我希望DRF通過當前登錄的用戶填充用戶字段。如何在Django Rest Framework中將當前用戶設置爲用戶字段?

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,) 

我該怎麼辦 這個?

回答

19

關閉我的頭頂,你可以重寫perform_create()方法:

class PhotoListAPIView(generics.ListCreateAPIView): 
    ... 
    def perform_create(self, serializer): 
     serializer.save(user=self.request.user) 

把那一個鏡頭,讓我知道,如果它

+1

嗨。如果我在'serializers.py'文件中使用'def validate_user(self,value): 返回self.context ['request']。user'會怎麼樣?這也起作用。這兩者之間有什麼內在的區別嗎? – MiniGunnR

+0

@MiniGunnR假設你希望用戶成爲序列化的一部分,這也可以。我的方法無論如何都會工作 – DaveBensonPhillips

1

您將不得不覆蓋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()沒有必要的,因爲你可以指定哪些字段是隻讀的,從你的序列化,但基於我工作過的項目,我通常用「不對稱」序列化,即根據不同的串行結束關於預期的操作。

3

@ 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) 
3

這取決於您的使用情況。如果你希望它是「只寫」,意思是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像這樣:

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) 
相關問題