python - 减少 django modelform 中的重复查询

标签 python django query-optimization query-performance

我有一个模型表单可以在基于函数的 View 中创建模型实例。 当创建 View 呈现表单模板时,它运行 6 个我想减少的查询。 有什么方法可以减少 qs 或提高模型创建 View 的性能吗?

models.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']

* forms.py *

class TeacherForm(ModelForm):
    class Meta:
        model = Teacher
        fields = ['name', 'photo', 'date_of_birth',
                  'designation', 'expertise',
                  'mobile', 'email', ]

*views.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。当 modelform 中有关系字段时,django modelform 字段会在 request.get 方法中运行重复查询。事实上,我们通过手动提供数据来防止字段运行重复查询。

models.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和experience_choices :

        designation_choices = Designation.objects.values_list('id', 'name')
        expertise_choices = Topic.objects.values_list('id', 'name')

这非常快,因为查询 Designation 或 Topic 的所有字段时只查询其中的两个字段。

更深入

(通过引用 django 类(class)代码来回答,仅供阅读):

django modelform 创建表单字段 ModelChoiceField、ForeignKey 的 ModelMultipleChoiceField、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)

关于python - 减少 django modelform 中的重复查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59116235/

相关文章:

python - JIT 编译函数中的任意精度算法

python - 如何通过 Python 将 🍒 添加到我的 VARCHAR 字段

python - 无法从 request.session 中通过键获取值;我用Django

database - 创建索引并没有改变我的查询成本

mysql - 了解 MySQL 查询优化器

python - 如何获取 csv 文件的子集作为 Spark RDD

django - 集成 Django 和 Twitter Bootstrap

python - Django Rest Framework 从模型获取序列化器

Django:单击图像并在新页面中打开它

MySQL DELETE 查询性能调优