许多数据库查询模型对象的字符串表示形式

时间:2019-02-17 03:05:26

标签: django django-models

我有这个模型:

class Country(models.Model):
    name = models.CharField(max_length=250)

    def __str__(self):
        return str(self.name)

class City(models.Model):
    name = models.CharField(max_length=250)
    country = models.ForeignKey(Country, default=None, blank=True)

    def __str__(self):
        return str(self.name)

class Airport(models.Model):
    name = models.CharField(max_length=250)
    city = models.ForeignKey(City, default=None, blank=True)

    def __str__(self):
        return "{0} - {1} - {2}".format(self.city, self.city.country, self.name)

class Tour(models.Model):
    title = models.CharField(max_length=200)
    tour_from = models.ForeignKey(Airport)
    tour_to = models.ForeignKey(Airport)

    def __str__(self):
        return str(self.title)

对于Airport的字符串表示形式,Django向DB发送了许多请求:

  

302.06毫秒(591个查询,包括586个相似项和586个重复项)

查询屏幕截图: enter image description here

tour/create页上,我有一个用于创建游览的ModelForm,而Django发送这些查询以显示表单。

forms.py:

class TourCreateForm(forms.ModelForm):
    class Meta:
        model = Tour
        fields = ['title', 'tour_from', 'tour_to']

views.py:

class DashboardTourCreate(CreateView):
    model = Tour
    template_name = "dashboard/tour/create.html"
    form_class = TourCreateForm

    def get_context_data(self, **kwargs):
        context = super(DashboardTourCreate, self).get_context_data(**kwargs)
        context['page_name'] = ['tour', 'tour-index']
        context['page_title'] = "Create Tour"
        return context

如何减少查询数量?

3 个答案:

答案 0 :(得分:2)

根本原因

def __str__(self):
    return "{0} - {1} - {2}".format(self.city, self.city.country, self.name)

tour_to小部件中将tour_from<option>字段呈现为<select>时,将调用Airport.__str__方法。由于Airport.__str__具有self.city.county,并且两者都是ForeignKey,因此Django ORM发出查询以获取机场城市和城市国家。

它对每个Airport的每个<option>都执行此操作,这意味着添加的Airport越多,问题就会变得越来越严重。

解决方案

利用select_related [1]。 select_related会告诉Django ORM每当抓住('city', 'county')时就拉入相关字段Airport

class TourCreateForm(forms.ModelForm):
    class Meta:
        model = Tour
        fields = ['title', 'tour_from', 'tour_to']

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.fields['tour_from'].queryset = Airport.objects.select_related(
            'city__country',
        )

        self.fields['tour_to'].queryset = Airport.objects.select_related(
            'city__country',
        )

[1] https://docs.djangoproject.com/en/2.1/ref/models/querysets/#select-related

答案 1 :(得分:0)

由于f字符串是在运行时link中计算的字符串文字表达式,因此它可能比其他字符串格式更快,但我不确定。我希望进行以下修改可以减少总时间。

class Airport(models.Model):
    name = models.CharField(max_length=250)
    city = models.ForeignKey(City, default=None, blank=True)

    def __str__(self):
        return f"{self.city} - {self.city.country} - {self.name}"

答案 2 :(得分:0)

我通过将Queryset添加到forms.py来解决此问题:

class TourCreateForm(BaseForm):
    airports = Airport.objects.select_related('city', 'city__country').all()

    tour_from = forms.ModelChoiceField(queryset=airports)
    tour_to = forms.ModelChoiceField(queryset=airports)

但是我认为这是不正确的!