我正在开发一个具有一些社交功能的项目,并且需要做到这一点,以便用户可以查看他的个人资料的所有详细信息,但只能查看其他人的公开部分'配置文件。
有没有办法在一个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?
答案 0 :(得分:1)
我们可以覆盖retrieve()
中的list
和ProfileViewSet
方法,以根据所查看的用户返回不同的序列化数据。
在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
答案 1 :(得分: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
视图,我非常感谢你的答案。