You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django如何获取关联同一外键Address的Persons与Places合并QuerySet

解法说明

Django的QuerySet默认仅支持返回单一模型的结果,针对你的需求分两种常见场景给出实现方式:

场景1:基于已赋值的Persons实例,查询同地址的所有Places并关联带出对应Persons数据

假设你已经拿到了adress不为空的Persons实例person_obj,可以通过如下方式查询:

# 方法1:用select_related提前关联Adress,再过滤同地址的Places,同时通过反向查询取Persons数据
place_qs = Places.objects.filter(adress_id=person_obj.adress_id).select_related("adress")
# 遍历的时候可以直接取关联的Persons数据(Django会自动生成Persons的反向关联名称persons_set,如果你没指定related_name的话)
for place in place_qs:
    # 同地址的所有Persons对象
    related_persons = place.adress.persons_set.all()
    # 当前的Persons实例匹配项
    target_person = related_persons.filter(id=person_obj.id).first()

如果要简化反向查询,建议你给外键加related_name参数,修改模型如下:

class Persons(models.Model):
    adress = models.ForeignKey(Adress, on_delete=models.DO_NOTHING, blank=True, null=True, related_name="persons")
class Places(models.Model):
    adress = models.ForeignKey(Adress, on_delete=models.DO_NOTHING, related_name="places")

修改后查询代码可以简化为:

place_qs = Places.objects.filter(adress=person_obj.adress).prefetch_related("adress__persons")

场景2:需要同时返回Persons和Places两种模型的合并结果

如果要求返回的QuerySet同时包含两种模型的实例,可以用union方法,前提是两个查询返回的字段数量、类型完全一致:

from django.db.models import F, Value, CharField

# 构造Persons的查询,添加标记字段区分类型
person_qs = Persons.objects.filter(adress__isnull=False).annotate(
    obj_type=Value("person", output_field=CharField()),
    data_id=F("id"),
    adress_data=F("adress__some_data")
).values("obj_type", "data_id", "adress_data")

# 构造Places的查询,保持返回字段和上面完全一致
place_qs = Places.objects.annotate(
    obj_type=Value("place", output_field=CharField()),
    data_id=F("id"),
    adress_data=F("adress__some_data")
).values("obj_type", "data_id", "adress_data")

# 合并两个QuerySet
combined_qs = person_qs.union(place_qs)

如果你只需要某个指定Persons实例对应的合并结果,只要给两个查询加上过滤条件filter(adress_id=person_obj.adress_id)即可。

内容的提问来源于stack exchange,提问作者SamPhoenix

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 21:36:04