Django关联模型表单显示时重复数据库查询问题优化咨询
解决Django表单下拉框重复查询问题
问题场景
使用CreateView结合关联FilesData模型的SendRnxForm表单时,表单中的el_type下拉框会重复执行查询ElType表的SQL语句,产生不必要的数据库请求。
相关代码
模型定义
class ElType(models.Model): name = models.CharField(max_length=16, db_index=True, verbose_name="Types el") slug = models.SlugField(max_length=24, unique=True, db_index=True, verbose_name="Код") def __str__(self): return self.name class FilesData(models.Model): el_type = models.ForeignKey(ElType, blank=False, default='1', on_delete=models.DO_NOTHING, related_name='files', verbose_name="Types el")
表单定义
class SendRnxForm(forms.ModelForm): class Meta: model = FilesData fields = ['el_type',] widgets = { 'el_type': forms.Select(attrs={'class': 'form-select', 'id': 'elTypeId'}), }
视图定义
class dashForm(DataMixin, CreateView): form_class = SendRnxForm template_name = 'dashApp/dash.html' success_url = reverse_lazy('home')
解决方案
重复查询的根源是ModelForm默认会在每次访问字段的queryset时执行数据库查询,若表单被多次初始化(比如模板重复渲染、视图逻辑多次调用),就会触发重复请求。我们可以通过提前缓存ElType的查询结果来解决,当前场景无需使用select_related或prefetch_related(仅需获取ElType自身数据,无跨模型关联查询需求)。
方案1:重写表单的__init__方法
在表单初始化时一次性获取ElType数据并赋值给字段,确保仅执行一次查询:
class SendRnxForm(forms.ModelForm): class Meta: model = FilesData fields = ['el_type',] widgets = { 'el_type': forms.Select(attrs={'class': 'form-select', 'id': 'elTypeId'}), } def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # 一次性获取所有ElType记录并排序 el_type_queryset = ElType.objects.all().order_by('id') self.fields['el_type'].queryset = el_type_queryset # 设置默认选中第一条记录(可选,根据需求调整) if el_type_queryset.exists(): self.fields['el_type'].initial = el_type_queryset.first().id
方案2:在视图中重写get_form方法
在视图层提前获取ElType数据,传递给表单字段:
class dashForm(DataMixin, CreateView): form_class = SendRnxForm template_name = 'dashApp/dash.html' success_url = reverse_lazy('home') def get_form(self, form_class=None): form = super().get_form(form_class) # 预加载ElType数据 el_type_queryset = ElType.objects.all().order_by('id') form.fields['el_type'].queryset = el_type_queryset # 设置默认选中第一条记录(可选) if el_type_queryset.exists(): form.fields['el_type'].initial = el_type_queryset.first().id return form
说明
两种方案本质都是通过提前执行一次查询并复用结果,避免每次表单初始化时重复触发数据库请求。当前场景无需使用select_related或prefetch_related,因为我们仅需查询ElType模型本身,没有涉及跨模型的关联数据获取。
内容的提问来源于stack exchange,提问作者Arterium
相关产品推荐
相关产品推荐

