Django 多对多关系,双向包含查询集中的所有 ID

Django many to many relation, include all IDs in queryset in both directions

我有 2 个模型通过 M2M 关系连接

class Paper(models.Model):
  title = models.CharField(max_length=70)
  authors = models.ManyToManyField(B, related_name='papers')

class Author():
  name = models.CharField(max_length=70)
Author.objects.all().annotate(related_papers=F('papers'))

这只添加了一篇论文的 id,我认为是它找到的第一个。

此外,将related_papers更改为papers会出现错误:

ValueError: The annotation ‘papers’ conflicts with a field on the
model.

其实已经帮你实现了。您应该像这样在 Paper 模型中包含与作者的多对多关系:

class Paper(models.Model):
  title = models.CharField(max_length=70)
  authors = models.ManyToManyField(Author, related_name='papers')

这使您有机会使用以下方法将 Author 个对象添加到相关集合 p.authors.add(u),假设pPaper模型的对象,aAuthor模型的对象。

  • 您可以使用 p.authors.all().
  • 访问 Paper 实例的所有相关作者
  • 您可以使用 u.papers.all().
  • 访问 Author 个实例的所有相关论文

这将 return 一个您可以操作的 QuerySet 实例。


查看此 documentation 页面以了解更多信息。

根据我在您的评论中了解到的情况,您使用的是 DRF。我会给你2个答案。

1) 如果你在谈论模型序列化器,你可以使用 PrimaryKeyRelatedField :

class AuthorSerializer(serializers.ModelSerializer):
    papers=serializers.PrimaryKeyRelatedField(many=True, read_only=True)

    class Meta:
        model = Author
        fields = ['name', 'papers']

class PaperSerializer(serializers.ModelSerializer):
    class Meta:
        model = Paper
        fields = '__all__'

这将 return 关系另一方的 ID,无论您是在论文方还是作者方。这将 return 主键,而不是对象本身的表示。

2) 现在你也在谈论性能(例如,每次迭代都会命中数据库)。

Django(非 DRF 特定)有一个查询集方法来处理预加载相关对象。它被称为 prefetch_related

例如,如果您知道您将需要关系对象属性并且希望避免重新查询数据库,请执行以下操作:

Author.objects.all().prefetch_related('papers') 
# papers will be already loaded, thus won't need another database hit if you iterate over them.