Django ORM展示多关联对象问题:仅显示部分Contract对象求助
问题:Django ORM关联对象展示与分页异常
问题背景
我尝试用Django ORM展示多个关联对象,原代码逻辑如下:
if co is None: try: address = Contract.objects.filter(address= servicesearch) print(address) except Contract.DoesNotExist: address= None for add in address: co = add.contractservices_set.all() print(co)
首次查询得到QuerySet:
return (<QuerySet [<Contract: Contract object (52)>, <Contract: Contract object (55)>]> )
循环查询得到两个Contractservices的QuerySet:
return (<QuerySet [<Contractservices: Contractservices object (88)>, <Contractservices: Contractservices object (89)>, <Contractservices: Contractservices object (90)>, <Contractservices: Contractservices object (91)>]> <QuerySet [<Contractservices: Contractservices object (98)>, <Contractservices: Contractservices object (101)>, <Contractservices: Contractservices object (102)>, <Contractservices: Contractservices object (99)>, <Contractservices: Contractservices object (103)>, <Contractservices: Contractservices object (100)>, <Contractservices: Contractservices object (104)>]> )
查询结果正常,但渲染时仅显示Contract对象55的内容,我需要同时展示52和55这两个Contract对象。分页器代码如下:
paginator = Paginator(co,8) if request.GET.get('page') == None: page_number = 1 else: page_number =request.GET.get('page') DataFinal=paginator.get_page(page_number) totalpage =DataFinal.paginator.num_pages
且无法修改模板,因为这只是众多搜索条件之一,需要解决该问题。
问题原因
循环中每次给co赋值时,都会覆盖之前的QuerySet,最终co仅保留了最后一个Contract(id=55)的contractservices数据,导致分页和渲染时只显示这部分内容。
解决方案
方法1:合并所有关联对象QuerySet
通过收集所有Contract对应的contractservices,再合并为一个可迭代对象(兼容分页器):
from itertools import chain if co is None: try: address = Contract.objects.filter(address=servicesearch) print(address) except Contract.DoesNotExist: address = None # 收集所有Contract对应的contractservices services_list = [] for add in address: services_list.append(add.contractservices_set.all()) # 合并为一个列表(分页器支持列表类型) co = list(chain(*services_list))
方法2:反向查询(更高效,避免N+1问题)
直接从Contractservices模型反向筛选关联Contract符合条件的记录,仅需1次数据库查询:
if co is None: # 直接查询所有属于address匹配的Contract的Contractservices co = Contractservices.objects.filter(contract__address=servicesearch) print(co)
两种方法修改后,co都会包含Contract 52和55对应的所有Contractservices数据,分页渲染时即可展示全部内容,且无需修改现有模板和分页代码。
内容的提问来源于stack exchange,提问作者Arghya Dasmahapatra
相关产品推荐
相关产品推荐

