python - 减少 django modelform 中的重复查询
问题描述
我有一个模型表单来在我的基于函数的视图中创建模型实例。当创建视图呈现表单模板时,它会运行 6 个我想减少的查询。有什么办法可以减少 qs 或提高模型创建视图的性能?
模型.py
class Teacher(models.Model):
name = models.CharField(max_length=150)
photo = models.ImageField(upload_to='teachers',
default='teacheravatar.jpg')
date_of_birth = models.DateField(blank=True, null=True)
designation = models.ForeignKey(Designation, on_delete=models.CASCADE)
expertise = models.ManyToManyField(
to=Topic, blank=True, related_name='expert_in')
mobile = models.CharField(max_length=11, blank=True, null=True)
email = models.CharField(max_length=255, blank=True, null=True)
joining_date = models.DateField(auto_now=True)
class Meta:
ordering = ['joining_date', 'name']
* 表格.py *
class TeacherForm(ModelForm):
class Meta:
model = Teacher
fields = ['name', 'photo', 'date_of_birth',
'designation', 'expertise',
'mobile', 'email', ]
* 视图.py *
# THIS VIEW DUPLICATES QUEREIS
# AND RUNS 6 QUERIES
@login_required
def add_teacher_view(request):
"""
:param request:
:return: teacher add form
"""
if request.method == 'POST':
form = TeacherForm(request.POST)
if form.is_valid():
form.save()
pk = form.instance.pk
return redirect('teachers:teacher_details', pk=pk)
form = TeacherForm()
context = {'form': form}
return render(request, 'teachers/add_teacher.html', context)
解决方案
您应该在关系字段上定义 .choices。当您在模型表单中有关系字段时,django 模型表单字段在 request.get 方法中运行重复查询。事实上,我们通过手动提供数据来防止字段运行重复查询。
模型.py
class TeacherForm(ModelForm):
class Meta:
model = Teacher
fields = ['name', 'photo', 'date_of_birth',
'designation', 'expertise',
'mobile', 'email', ]
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
designation_choices = [(designation.id, designation.__str__()) for designation in Designation.objects.all()]
expertise_choices = [(topic.id, topic.__str__()) for topic in Topic.objects.all()]
self.fields['designation'].choices = designation_choices
self.fields['expertise'].choices = expertise_choices
我建议您在所有模型中定义str,例如,假设您在所有模型的str中返回 self.name,您可以像这样定义 designation_choices 和 knowledge_choices:
designation_choices = Designation.objects.values_list('id', 'name')
expertise_choices = Topic.objects.values_list('id', 'name')
这是如此之快,因为查询所有字段的名称或主题只查询其中的两个字段。
更深
(通过参考 django 课程代码来回答,仅供阅读):
django modelform 创建表单字段 ModelChoiceField、ModelMultipleChoiceField for ForeignKey、ManyToManyField 字段。这两个字段都使用方法 _get_choices 来创建那些重复的查询。
由 self.iterator(self) 运行的重复查询这里的关键是当提供 _choices 时,默认查询(重复查询)将停止。此处的属性选择将填充变量 _choices 并删除重复的查询。
django.forms.models.py
def _get_choices(self):
# If self._choices is set, then somebody must have manually set
# the property self.choices. In this case, just return self._choices.
if hasattr(self, '_choices'):
return self._choices
# Otherwise, execute the QuerySet in self.queryset to determine the
# choices dynamically. Return a fresh ModelChoiceIterator that has not been
# consumed. Note that we're instantiating a new ModelChoiceIterator *each*
# time _get_choices() is called (and, thus, each time self.choices is
# accessed) so that we can ensure the QuerySet has not been consumed. This
# construct might look complicated but it allows for lazy evaluation of
# the queryset.
return self.iterator(self)
choices = property(_get_choices, ChoiceField._set_choices)
推荐阅读
- powershell - PowerShell脚本计划任务根据设置密码更改本地用户密码值
- python - 我应该如何编写一个 XPath 来提取我需要的内容?
- r - 连接两个数据帧时检查所有值是否已连接的参数
- javascript - 必需属性不适用于 addEventListener?
- php - Symfony:如何检查表单发送的数据
- excel - 如何在使用 EDATE 公式的同时大写日期月份
- image - 训练、测试和标记单独的文件夹
- javascript - 我想通过使用脚本来避免谷歌表格中的重复日期
- python - 我哪里做错了?(我是初学者),我该如何做对?
- python - Python - 如何在不使用堆栈和类的情况下检查有向无环图?