Django Admin多对多内联视图出现过多SQL查询问题排查求助
问题根源
你遇到的是典型的Django ORM N+1查询问题,现有配置无效的原因有两个:
list_select_related是普通ModelAdmin列表页的专属属性,TabularInline内联组件不识别该参数,加了也不会生效。- 你定义的
AlignedScan_Manager没有绑定到AlignedScan模型上,所以查询时完全不会调用这个管理器的自定义查询逻辑。
每条AlignedScan记录触发的两次查询,分别是访问外键scan和alignment时产生的单次查询,N条记录就会生成2N次冗余查询,是导致页面加载慢的直接原因,和你是否展示关联字段没有关系。
修复方案
按以下步骤修改即可彻底消除冗余查询:
1. 绑定自定义管理器到AlignedScan模型(可选,直接在内联中重写查询集也可)
给AlignedScan补充自定义管理器的绑定声明,同时调整关联字段覆盖所有需要用到的外键:
class AlignedScan(models.Model): registered = models.BooleanField() x = models.FloatField(blank=True, null=True,) y = models.FloatField(blank=True, null=True,) z = models.FloatField(blank=True, null=True,) #... alignment = models.ForeignKey( Alignment, related_name='alignedscans', on_delete=models.CASCADE, ) scan = models.ForeignKey( Scan, related_name='alignedscans', on_delete=models.CASCADE, ) # 新增:绑定自定义管理器 objects = AlignedScan_Manager() class AlignedScan_Manager(models.Manager): def get_queryset(self): # 一次性关联scan和alignment两个外键,后续访问不会触发额外查询 # 如果后续要展示Scan/Alignment所属的ScanProject字段,改成select_related('scan__scanproject', 'alignment__scanproject') return super().get_queryset().select_related('scan', 'alignment')
2. 重写内联的get_queryset方法(最稳妥的方案,不需要自定义管理器也可单独使用)
直接在内联类中定义查询逻辑,确保关联查询生效:
class AlignedScan_Inline(admin.TabularInline): verbose_name = 'Scan' verbose_name_plural = 'Scans' model = AlignedScan fk_name = 'alignment' fields = ('registered', 'x', 'y', 'z') readonly_fields = ('registered', 'x', 'y', 'z') extra = 0 show_change_link = True # 新增:重写查询集,提前关联所有外键 def get_queryset(self, request): qs = super().get_queryset(request) # 按需调整关联字段,后续要展示Scan的name等字段也不需要额外加查询 return qs.select_related('scan', 'alignment') def has_add_permission(self, request, owner): return False def has_change_permission(self, request, owner): return True def has_delete_permission(self, request, owner): return False
修改后所有AlignedScan关联的scan、alignment数据都会在初始查询时一次性取出,不会再产生单条冗余查询。
内容的提问来源于stack exchange,提问作者Angelika Sajani
相关产品推荐
相关产品推荐

