
它深入探究了于其中怎样高效地去执行父子表的左连接查询, 目的是获取全部父记录以及与之关联的子记录, 这里所说的父记录包含那些不存在子记录的情况, 我们对和原始SQL查询的局限进行了对比, 着重介绍了ORM所提供的方法, 阐释了其工作原理、具备的优势以及在防止数据冗余和优化数据库查询这方面所起到的作用, 还给出了清晰的代码示例, 要理解其中的关联查询需求。在数据库应用开发之中, 我们常有查询关联表数据的需求。一个惯常出现的场景是, 我们要获取全部父表记录, 并且附带查询其关联的子表记录, 即使存在某些没有对应子表记录的父表记录, 也应当被纳入到结果里。这在sql中间通常靠left join左连接达成。例如, 存有State州与City城市这两个模型, 一个州能够存在多个城市, 我们的目的是去获取所有州的信息, 以及它们所包含的城市信息, 其中涵盖那些暂时不存在城市的州。模型定义from django.db import models class State(models.Model): name models.CharField(max_length25) abbreviation models.CharField(max_length2) def __str__(self): return self.name # 更好的__str__表示 class City(models.Model): name models.CharField(max_length25) population models.IntegerField() state models.ForeignKey(State, related_namecities, on_deletemodels.CASCADE) def __str__(self): return self.name # 更好的__str__表示的局限性ORM给提供了用于对关联查询予以优化的方法, 它借助于在数据库层面执行因应字段可空性而有所不同的INNER JOIN或者LEFT JOIN, 把关联对象具体的数据纳入同一的查询而来的结果当中, 进而达成减少数据库查询次数这一目的。cities_states City.objects.all().select_related(state).order_by(state_id)然而, 其主要限制在于, 它主要被运用在“一对一”或者“多对一”关系的反向查询方面也就是从子模型去查询父模型, 并且它的默认行为更趋近于INNER JOIN。这表明, 要是一个State不存在关联的City, 那么这个State将不会现身于查询结果里面。这跟我们所期望的, “获取所有State, 涵盖没有City的State”的左连接需求不相契合。原始SQL查询的挑战开发者在ORM没办法直接去满足复杂查询这个所需必要条件时, 或许就会萌生出考虑开始运用.raw()该项方法去执行原始SQL查询咯, 会有这样想而可能产生行为的情况出现。sql SELECT S.*, C.* FROM state S LEFT JOIN city C ON (S.id C.state_id) ORDER BY S.id ASC cities_states State.objects.raw(sql) for obj in cities_states: print(obj)这种方式的确能够达成标准的LEFT JOIN, 然而随之引发的却是几个疑问, 是这样几个问题呢, 这几个问题随之就产生了。处理字段名冲突时, 若父表跟子表都存在相同名字的字段比如id、name, 该有则raw()形式查找返回得到的对象会优先采用父表也就是State的那些字段值。举例来说, obj.name将会一直返回State的名称, 然而没办法直接借由obj.或者类似这样的方式去访问City的名称, 除非在SQL查询里给City的字段设定别名像。ORM对象整合方面, raw()查询返回的这般其中的每一个元素都是一个模型实例。虽说能够对其字段予以访问, 然而它并非全然等同于一个完整无缺的 ORM 对象, 没办法直接去调用关联方法, 就像 obj..all() 这种, 数据存在冗余情况, 原始 SQL 的 LEFT JOIN 会针对每个关联的子记录将父记录的数据进行重复, 要是一个州存在多个城市, 那么州的信息会在结果集中被再三重复, 如此一来便会使数据库传输的数据量有所增加, 并且也会消耗客户端的内存, 特别是在处理数量众多的数据时, 效率会大幅降低, 至于 ORM 的推荐方案。关于解决上述问题, 以及高效达成类似左连接那般的父子数据获取, ORM给出了方法, 此方法是针对处理“一对多”关系的最佳实践, 是针对处理“多对多”关系的最佳实践, 也是针对处理“泛型外键”关系的最佳实践。工作原理3.14.23.在2025年12月5日发布的编程语言稳定版本是14.2 , 它属于3.14系列的第二个维护更新。18项修复被包含在该版本中 , 主要解决了像多进程 、数据类以及正则表达式等模块的回归问题。安全漏洞如CVE - 2025 - 12084等也被修复。这个版本标志着自由线程模式移除GIL正式得到官方支持 , 是发展的重要里程碑。下载与在数据库层面执行JOIN不同的工作方式是进行主查询时: 最开始, 它会去执行一个单独独立的查询, 以此来获取主模型, 比如说像State这样的所有实例。开展关联查询时: 接下来, 它会去执行一个亦或是多个单独独立的查询, 进而获取所有关联模型, 就像City这样的实例, 并且依据主查询的结果去实现过滤。实施端连接时: 最终, 在内存里会把这些关联对象“连接”到其各自的主模型实例之上。数据库层面的大量JOIN操作可带来性能开销以及数据冗余, 而这种方法避免了这些, 对于左连接场景而言, 它能确保所有父记录都被获取, 哪怕它们没有关联的子记录。示例代码# 使用 prefetch_related 获取所有State及其关联的City states State.objects.prefetch_related(cities) for state in states: print(f州: {state.name} ({state.abbreviation})) # state.cities.all() 不会触发额外的数据库查询因为它已经被预取了 if state.cities.exists(): # 检查是否有城市 for city in state.cities.all(): print(f - 城市: {city.name}, 人口: {city.population}) else: print( - 暂无城市记录) # 预期输出示例 # 州: Texas (TX) # - 城市: Dallas, 人口: 1259404 # - 城市: Houston, 人口: 2264876 # 州: California (CA) # - 城市: Los Angeles, 人口: 3769485 # 州: Illinois (IL) # - 暂无城市记录在这个例子中State..()会执行两个数据库查询“state”表取出“state”列为“id”的内容, 同时取出“state”列为“name”的内容, 还有别的 , 从“state”表获取。“city”表取出“city”列为“id”的内容, 取出“city”列为“name”的内容, 还有别的 , 还有别的 , 从“city”表获取。条件是“city”有某内容处于1、2、3之中 假设查询所得的State ID是1、2、3。随后, 会于内存里把这些城市分派给相应的州对象。当您去访问state..all()之时, 不会再引发新的数据库查询举动, 由于相关数据已然被预先加载了。优势方面要注意的事项以及最佳做法是躲避彻底地过度去预取, 仅仅预取你切实确实需要的数据, 预取过多没什么必要的数据会致使增加内存的消耗, 存在链式调用的情况, 能够进行链式来调用, 去预取多层的关系, 举例来说, State..(), 另外还支持更为高级的自定义预取方式, 像是运用对象去实施更精细的把控, 比如对预取的数据予以过滤或者运用自定义的查询集。总结。就中达成父子表的左连接查询行为动作, 且高效率地去获取全部的父记录以及其可能存在的可选子记录情况形势所在之处所, 是较另一种或者原始SQL那种查询更为具备优越特点益处优势特征的解决办法方案举措, 此种办法方案举措借助巧妙地把数据库查询予以划分分成两步步骤过程并且于内存里面当中达成完成关联, 有效地切实地杜绝防范了数据多重重复冗余情况且削减降低了数据库运行负载, 并且还提供给出了清晰明白、契合符合ORM习惯惯例的代码, 明白理解并且正确无误地去运用操作是编写达成高性能应用项目的关键重点要点所在啊处所。