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
相关产品推荐
相关产品推荐

