2015-10-18 25 views
3

我正在開發一些具有社交功能的項目,並且需要讓用戶看到他的個人資料的所有詳細信息,但只能看到其他人的個人資料的公開部分。
有沒有辦法在一個ViewSet中做到這一點?在一個ViewSet中以每個對象爲基礎更改序列化程序?

這裏是我的模型的樣本:

class Profile(TimestampedModel): 
    user = models.OneToOneField(User) 

    nickname = models.CharField(max_length=255) 
    sex = models.CharField(
     max_length=1, default='M', 
     choices=(('M', 'Male'), ('F', 'Female'))) 

    birthday = models.DateField(blank=True, null=True) 

對於這種模式,我想生日,例如,留民營。
在實際模型中有大約十幾個這樣的字段。

我的串行:

class FullProfileSerializer(serializers.ModelSerializer): 
    class Meta: 
     model = Profile 


class BasicProfileSerializer(serializers.ModelSerializer): 
    class Meta: 
     model = Profile 
     fields = read_only_fields = ('nickname', 'sex', 'birthday') 

自定義權限我寫道:

class ProfilePermission(permissions.BasePermission): 
    """ 
    Handles permissions for users. The basic rules are 

    - owner and staff may do anything 
    - others can only GET 
    """ 

    def has_object_permission(self, request, view, obj): 
     if request.method in permissions.SAFE_METHODS: 
      return True 
     else: 
      return request.user == obj.user or request.user.is_staff 

我的視圖集:

class RUViewSet(
     mixins.RetrieveModelMixin, mixins.UpdateModelMixin, 
     mixins.ListModelMixin, viewsets.GenericViewSet): 
    """ViewSet with update/retrieve powers.""" 


class ProfileViewSet(RUViewSet): 
    model = Profile 
    queryset = Profile.objects.all() 
    permission_classes = (IsAuthenticated, ProfilePermission) 

    def get_serializer_class(self): 
     user = self.request.user 
     if user.is_staff: 
      return FullProfileSerializer 
     return BasicProfileSerializer 

我想是request.user自己的個人資料在要使用FullProfileSerializer序列化的查詢集中,但其餘的使用BasicProfileSerializer
這是否可以使用DRF的API?

回答

1

我們可以覆蓋我們的ProfileViewSet中的retrieve()list方法,根據查看的用戶返回不同的序列化數據。

list方法中,我們使用從get_serializer_class()方法返回的序列化程序對除當前用戶之外的所有用戶實例進行序列化。然後,我們使用FullProfileSerializer顯式地序列化當前用戶配置文件信息,並將此序列化數據添加到之前返回的數據中。

retrieve方法中,我們在視圖上設置了一個accessed_profile屬性,以瞭解視圖顯示的用戶。然後,我們將使用該屬性來決定get_serializer_class()方法中的序列化程序。

class ProfileViewSet(RUViewSet): 
    model = Profile 
    queryset = Profile.objects.all() 
    permission_classes = (IsAuthenticated, ProfilePermission) 

    def list(self, request, *args, **kwargs): 
     instance = self.filter_queryset(self.get_queryset()).exclude(user=self.request.user) 
     page = self.paginate_queryset(instance) 
     if page is not None: 
      serializer = self.get_pagination_serializer(page) 
     else: 
      serializer = self.get_serializer(instance, many=True) 
     other_profiles_data = serializer.data # serialized profiles data for users other than current user 
     current_user_profile = <get_the_current_user_profile_object> 
     current_user_profile_data = FullProfileSerializer(current_user_profile).data 
     all_profiles_data = other_profiles_data.append(current_user_profile_data) 
     return Response(all_profiles_data) 

    def retrieve(self, request, *args, **kwargs): 
     self.accessed_profile = self.get_object() # set this as on attribute on the view 
     serializer = self.get_serializer(self.accessed_profile) 
     return Response(serializer.data) 

    def get_serializer_class(self): 
     current_user = self.request.user 
     if current_user.is_staff or (self.action=='retrieve' and self.accessed_profile.user==current_user): 
      return FullProfileSerializer  
     return BasicProfileSerializer 
+0

這似乎是最乾淨的方式來做到這一點,而不需要深入串行器內部,謝謝。 –

0

我設法破解在一起,提供了detail視圖想要的問題的解決方案:

class ProfileViewSet(RUViewSet): 
    model = Profile 
    queryset = Profile.objects.all() 
    permission_classes = (IsAuthenticated, ProfilePermission) 

    def get_serializer_class(self): 
     user = self.request.user 
     if user.is_staff: 
      return FullProfileSerializer 
     return BasicProfileSerializer 

    def get_serializer(self, instance=None, *args, **kwargs): 

     if hasattr(instance, 'user'): 
      user = self.request.user 

      if instance.user == user or user.is_staff: 
       kwargs['instance'] = instance 
       kwargs['context'] = self.get_serializer_context() 
       return FullProfileSerializer(*args, **kwargs) 

     return super(ProfileViewSet, self).get_serializer(
      instance, *args, **kwargs) 

這並不爲list視圖工作,但是,作爲一個提供get_serializer方法有一個Django Queryset對象代替實際實例。
我仍然希望在list視圖中看到這種行爲,即序列化許多對象時,如果有人知道更優雅的方式來做到這一點,也涵蓋了list視圖,我非常感謝您的回答。