如何在Django中获取多对多关联双方的数据?
问题:获取指定Well及其关联的所有抗生素数据
模型定义
class Well(TimeStampMixin, models.Model): plate = models.ForeignKey(Plate, on_delete=models.CASCADE, related_name="wells") row = models.TextField(null=False) column = models.TextField(null=False) class Meta: unique_together = [["plate", "row", "column"]] class Antibiotic(TimeStampMixin, models.Model): name = models.TextField(null=True, default=None) class WellConditionAntibiotic(TimeStampMixin, models.Model): wells = models.ManyToManyField(Well, related_name="well_condition_antibiotics") volume = models.IntegerField(null=True, default=None) stock_concentration = models.IntegerField(null=True, default=None) dosage = models.FloatField(null=True, default=None) antibiotic = models.ForeignKey( Antibiotic, on_delete=models.RESTRICT, related_name="antibiotics" )
需求是获取指定Well的所有数据,以及其关联的全部Antibiotic数据。
已尝试的方法:
- 使用
WellConditionAntibiotic.objects.filter(wells__id=1).select_related('antibiotic'),能获取抗生素数据,但无法获取Well本身的数据。 - 使用
Well.objects.filter(pk=1).select_related(['well_condition_antibiotics', 'antibiotic']).query,出现错误。
解决方案
要同时获取Well数据和关联的抗生素数据,需要结合prefetch_related和select_related,核心逻辑如下:
- select_related 仅适用于外键/一对一关系,通过SQL JOIN一次性获取关联对象。
- prefetch_related 适用于多对多/反向外键关系,先查询主对象,再批量查询关联对象,避免N+1查询问题。
针对你的模型,well_condition_antibiotics是Well的多对多反向关联,需要用prefetch_related;而每个WellConditionAntibiotic关联一个Antibiotic(外键),可以用select_related提前获取。
正确查询语句
from django.db.models import Prefetch # 获取指定ID的Well,同时预取关联的WellConditionAntibiotic及对应的Antibiotic well = Well.objects.filter(pk=1).prefetch_related( Prefetch( 'well_condition_antibiotics', queryset=WellConditionAntibiotic.objects.select_related('antibiotic') ) ).first()
数据访问方式
- 访问Well自身数据:直接使用
well.row、well.column等属性。 - 访问关联的抗生素相关数据:
# 遍历所有关联的WellConditionAntibiotic对象 for wca in well.well_condition_antibiotics.all(): print(f"抗生素名称: {wca.antibiotic.name}") print(f"剂量: {wca.dosage}") print(f"体积: {wca.volume}")
该查询只会执行2次SQL:一次查询Well数据,一次批量查询关联的WellConditionAntibiotic和Antibiotic数据,避免了额外的数据库请求。
内容的提问来源于stack exchange,提问作者metersk
相关产品推荐
相关产品推荐

