我在StorySerializer中的GET /api/stories/169/
上收到以下错误,评论如下:
AttributeError at /api/stories/169/
'ManyRelatedField' object has no attribute 'queryset'
在检查物体后,我发现如果我改变了......
fields['feature'].queryset = fields['feature'].queryset.filter(user=user)
到
fields['photos'].child_relation.queryset = fields['photos'].child_relation.queryset.filter(user=user)
......似乎有效。但是这种方法没有记录,我确信这不是正确的做法。
我有这些模型:
class Story(CommonInfo):
user = models.ForeignKey(User)
text = models.TextField(max_length=5000,blank=True)
feature = models.ForeignKey("Feature", blank=True, null=True)
tags = models.ManyToManyField("Tag")
class Feature(CommonInfo):
user = models.ForeignKey(User)
name = models.CharField(max_length=50)
class Photo(CommonInfo):
user = models.ForeignKey(User)
image = ImageField(upload_to='photos')
story = models.ForeignKey("Story", blank=True, null=True, related_name='photos', on_delete=models.SET_NULL)
和StorySerializer
:
class StorySerializer(serializers.HyperlinkedModelSerializer):
user = serializers.CharField(read_only=True)
comments = serializers.HyperlinkedRelatedField(read_only=True, view_name='comment-detail', many=True)
def get_fields(self, *args, **kwargs):
user = self.context['request'].user
fields = super(StorySerializer, self).get_fields(*args, **kwargs)
## Restrict the options that the user can pick to the Features
## and Photos that they own
# This line works:
fields['feature'].queryset = fields['feature'].queryset.filter(user=user)
# This line throws the error:
fields['photos'].queryset = fields['photos'].queryset.filter(user=user)
return fields
class Meta:
model = Story
fields = ('url', 'user', 'text', 'comments', 'photos', 'feature', 'tags')
我做错了什么?我觉得这与ForeignKey
关系的方向有关。
答案 0 :(得分:0)
您可以尝试使用 drf-writable-nested package 代替覆盖 get_fields 方法,这将有助于更轻松地序列化嵌套关系并更好地处理 orm 字段方向。
答案 1 :(得分:0)
你可以使用 django-filter
我认为在序列化器中编辑 get 不是实用的解决方案
答案 2 :(得分:0)
重要的两点。
当从用户视图中过滤查询集时,所有外键对象检索将只生成特定用户的对象。因此无需过滤 get_fields
内的用户。
class StoryList(generics.ListAPIView):
serializer_class = StorySerializer
def get_queryset(self):
# consider there is login check before code is reaching here
# since this filtered by the user and any susbquent
# foreign key objects will belong only to this user
return Story.objects.filter(user=self.request.user)
一旦对用户进行过滤,您就可以使用另一个序列化程序或 SerializerMethodField
来相应地构造数据。以下代码应该适用于您的情况。
class UserSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
# Allow only url and id
fields = ['id', 'url']
extra_kwargs = {'url': {'view_name': 'user-detail'}}
class FeatureSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
fields = ['id', 'url']
extra_kwargs = {'url': {'view_name': 'feature-detail'}}
class PhotoSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
fields = ['id', 'url']
extra_kwargs = {'url': {'view_name': 'photo-detail'}}
class StorySerializer(serializers.HyperlinkedModelSerializer):
user = UserSerializer(read_only=True)
comments = serializers.HyperlinkedRelatedField(read_only=True,
view_name='comment-detail', many=True)
# this work because of related names
features = FeatureSerializers(many=True)
photos = PhotoSerializers(many=True)
# add tags serializer as well
text = serializers.CharField()
class Meta:
fields = ['id', 'users', 'photos', 'features', ...]
答案 3 :(得分:-1)
我遇到了类似的问题,找到了一个与嵌套序列化程序的默认查询集有关的解决方案(链接):How do you filter a nested serializer in Django Rest Framework?
而不是编辑get_fields
在故事序列化程序上,添加功能和照片字段,以引用故事序列化程序上的功能和照片序列化程序。
例如
StorySerializer:
features = FeatureSerializer(many=true, read_only=true)
然后为功能和照片覆盖list_serializer_class:
class FeatureFilteredListSerializer(serializers.ListSerializer):
def to_representation(self, data):
data = data.filter(user=self.context['request'].user)
return super(FeatureFilteredListSerializer, self).to_representation(data)
// And then reference this from the actual FeatureSerializer meta:
class FeatureSerializer(serializers.ModelSerializer):
...
class Meta:
model = Work
list_serializer_class = FeatureFilteredListSerializer
fields = (...)
然后,当您到达故事终点时,它将获得此过滤后的嵌套序列化器列表