首页 > 解决方案 > 如何使用多个重型 ModelChoiceFields 加速模板显示?

问题描述

通过一个django表格,我想显示相当多的ModelChoiceFields. 这些字段是相同的(显示相同的人员列表)。但是,问题是我在这些领域有很多条目。我拥有的字段越多,加载模板所需的时间就越多,即使我认为查询集(每个字段都相同)只会被评估一次。


假设和问题

我的假设是查询集的评估次数与必填字段的数量一样多。如果这是正在发生的事情,我不知道如何优化我的字段被初始化的方式


我想要什么我不想要什么


我的代码

from django import forms
from . import exceptions
from django.contrib.auth.models import Group, User

class MyForm(forms.Form):

    # defining a dict here, and using it in __init__ to define multiple fields within a loop
    # NOTE : 'pc{i}' will be the name of one of the fields. queryset for each is defined in __init__
    nb_pcs = 16
    pcs_dict = {}
    for i in range(1, nb_pcs + 1):
        pcs_dict.update({
            f'pc{i}': forms.ModelChoiceField(queryset=None, required=False)
        })

    def __init__(self, *args, **kwargs):
        
        # getting user through kwargs
        self.user = kwargs.pop('user', None)
        if not self.user: raise exceptions.DontKnowWhoFillsForm_Error()
        super(MyForm, self).__init__(*args, **kwargs)
        
        # defining the queryset that will be used for each field 'pc{i}'
        user_queryset = User.objects\
            .filter(groups__name='RegularAccount')\
            .order_by('last_name')

        # defining the fields themselves
        for key, value in self.pcs_dict.items():
            self.fields[key] = value 
            self.fields[key].queryset = user_queryset

非常感谢您的帮助!

标签: djangodjango-formsdjango-templates

解决方案


首先使用django-debug-toolbar找出导致页面变慢的原因 - 它可能是查询集(您已经解决了),但很可能是模板渲染。

您可以在视图中呈现ModelChoiceField后端的选项,然后使用render_to_string().

首先为您的选项创建一个模板。

# user_choice_field_options.html
{% for obj in queryset %}
  <option value="{{ obj.id }}">{{ obj.first_name }}</option>
{% endfor %}

然后在您的视图中,您将呈现选项并将其作为额外的上下文传递,以便它可以用作模板变量。

from django.template.loader import render_to_string
from django.views.generic import FormView

class MyView(FormView):
    template_name = 'my_template.html'
    form_class = MyForm

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        users = (
            User.objects
            .filter(groups__name='RegularAccount')
            .order_by('last_name')
        )
        context['user_options'] = render_to_string(
            'user_choice_field_options.html',
            context={'queryset': users},
            request=self.request,
        )
        return context

然后,my_template.html您可以根据需要手动多次渲染小部件。

<select name="field_1" required="" id="id_field_1">
  <option value="">---------</option>
  {{ user_options|safe }}
</select>

更进一步,您可以添加模板片段缓存


推荐阅读