【问题标题】:Django Request Framework 'ManyRelatedField' object has no attribute 'queryset' when modifying queryset in get_fields在 get_fields 中修改查询集时,Django 请求框架“ManyRelatedField”对象没有属性“查询集”
【发布时间】:2015-05-30 15:04:28
【问题描述】:

我在 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 关系的方向有关。

【问题讨论】:

  • 不确定,但可能是故事模型与照片模型之间没有关系,但照片与故事之间存在关系
  • 我也遇到了同样的问题。在 DRF 2.0 中,该字段没有子关系,因此您可以只使用 field.queryset 而不是 field.child_relation.queryset。现在的问题是,如果 child_relation 有可能嵌套,那么一个好的解决方案会很好。
  • 哦,没关系,它似乎没有无限嵌套,这是一个错误。尽管如此,一些官方的推理还是不错的。

标签: django django-rest-framework


【解决方案1】:

我遇到了类似的问题,并找到了与嵌套序列化程序的默认查询集有关的解决方案(已链接):How do you filter a nested serializer in Django Rest Framework?

而不是编辑get_fields 在您的故事序列化程序上添加引用故事序列化程序上的功能和照片序列化程序的功能和照片字段。 例如 故事序列化器: 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 = (...)

然后当你点击你的故事端点时,它会得到这个过滤的嵌套序列化器列表

【讨论】:

    【解决方案2】:

    您可以尝试drf-writable-nested package,而不是覆盖get_fields 方法,这将有助于更轻松地序列化嵌套关系并更好地处理orm 字段方向。

    【讨论】:

    • 欢迎来到 StackOverflow!我建议不要在答案中使用修辞问题。他们冒着被误解为根本不是答案的风险。您正在尝试回答此页面顶部的问题,不是吗?否则请删除此帖。
    • 我试图提供帮助,所以我建议了不同的方法
    • 是的,非常感谢。不问问题就这样做,你有被误解的风险。我们有一些非常狭隘的人,更不用说像机器人一样思考的用户,他们看到“?”时会发痒。在一个答案中。 (嗨,纳蒂,你不介意吧?;-))
    【解决方案3】:

    您可以使用 django-filter

    我认为在序列化器中编辑 get 不是实用的解决方案

    【讨论】:

      【解决方案4】:

      两个重点。

      1. 当从用户视图中过滤查询集时,所有外键对象检索将只产生特定用户的对象。所以不需要过滤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)
        
      2. 一旦对用户进行过滤,您就可以使用另一个序列化程序或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', ...]
        

      【讨论】:

        猜你喜欢
        • 2010-11-02
        • 2021-11-23
        • 2021-10-26
        • 2018-02-14
        • 2011-03-04
        • 2015-05-08
        • 2011-01-30
        • 1970-01-01
        • 2018-02-14
        相关资源
        最近更新 更多