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)
有没有一种方法可以将 authors
作为所有相关作者的 ID(并且可能以某种方式命名)包括在内?
有没有办法将 papers
ID 作为反向关系(可能还有标题)包含在内?
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)
,假设p
是Paper
模型的对象,a
是Author
模型的对象。
- 您可以使用
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.
我有 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)
有没有一种方法可以将
authors
作为所有相关作者的 ID(并且可能以某种方式命名)包括在内?有没有办法将
papers
ID 作为反向关系(可能还有标题)包含在内?
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)
,假设p
是Paper
模型的对象,a
是Author
模型的对象。
- 您可以使用
p.authors.all()
. 访问 - 您可以使用
u.papers.all()
. 访问
Paper
实例的所有相关作者
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.