多对多运行2n查询上的Django DRF序列化程序方法字段

多对多运行2n查询上的Django DRF序列化程序方法字段,django,django-rest-framework,many-to-many,django-orm,Django,Django Rest Framework,Many To Many,Django Orm,我正在使用Django 2.2和Django REST框架 我有以下模型结构 class MyModel(models.Model): name = models.ChartField(max_length=200) class Tag(models.Model): name = models.ChartField(max_length=50, unique=True) class MyModelRelation(models.Model): obj = models.Forei

我正在使用Django 2.2Django REST框架

我有以下模型结构

class MyModel(models.Model):
  name = models.ChartField(max_length=200)

class Tag(models.Model):
  name = models.ChartField(max_length=50, unique=True)

class MyModelRelation(models.Model):
  obj = models.ForeignKey(MyModel, related_name='relation')
  user = models.ForeignKey(User)
  tags = models.ManyToManyField(Tag)

  def tag_list(self):
     return self.tags.all().values_list('name', flat=True).distinct()
我想获得带有
MyModel
实例的标记列表,为此,序列化程序是

class MyModelSerializer(serializers.ModelSerializer):
  tags_list = serializers.SerializerMethodField(read_only=True)

  def get_tags_list(self, obj):
     return obj.relation.tag_list()

  class Meta:
    fields = [
      'name',
      'tags_list'
    ]
而这一观点是正确的

class ObjListView(ListAPIView):
  serializer_class = MyModelSerializer
  
  def get_queryset(self):
    return super().get_queryset().select_related('relation').prefetch_related('relation__tags')
但为了获得58条记录,它运行了近109个查询


my\u-app\u-mymodel`、`my\u-app\u-mymodel-relation\u标记
重复多次

这就是我建议您解决问题的方法。您可以在序列化程序级别提取名称,而不是在DB级别提取名称。这将使事情变得更容易、更快。首先,从模型类中删除
标记列表
方法。首先将注释添加到视图中: 从django.db.models导入F

def get_queryset(self):
    return super().get_queryset().annotate(tags_list=F('relation__tags')).select_related('relation')
然后在序列化程序中

class MyModelSerializer(serializers.ModelSerializer):
  tags_list = serializers.SlugRelatedField(many=True, slug_field='name', read_only=True)
...

这是由于模型类中的
tag\u list
方法造成的。对每个模型实例调用它,很可能调用两次。请注意,这些查询都是作为新的数据库查询运行的,因此您的select\u相关或prefetch\u相关没有帮助。您可以尝试注释
标记列表
,而不是使用方法。我在serializer method字段中使用了相同的逻辑,但查询数量仍然相同。你能给我一个带有注解的例子吗?检查我下面的答案,我给出的是
TypeError:“int”对象不可编辑
我没有运行这段代码,所以我没有意识到这些错误。你能至少找出类型错误的来源吗?堆栈跟踪应该向您显示我刚才看到我在注释中省略了一个括号。我不知道这是否是导致类型错误的原因,但您可以再试一次。如果您发现了一个错误,请尝试查看它的来源,并让我知道,因为我无法运行代码myselfbracket不是问题所在。在
Serializer
库中调试后,上述字段将转换为
ManyRelatedField(child\u relation=SlugRelatedField(read\u only=True,slug\u field='name'),read\u only=True)
,属性为整数,而不是可迭代的。
ManyRelatedField.to_representation()
需要一个可迭代的字段,但它得到的是一个整数。让我们来看看。