22

我的 Django 网站之一有以下数据库模型: 在 Django App “common” 中:

class Collection(models.Model):
    name = models.CharField(max_length = 255, unique = True)
    _short_name = models.CharField(db_column="short_name", max_length = 32, blank=True)

class Particle(models.Model):
    content = models.TextField(blank=False)
    owner = models.ForeignKey(Collection)
    order = models.IntegerField(null=True, blank=True)

在 Django 应用程序“情景喜剧”中:

class Media(models.Model):
    name = models.CharField(max_length = 248)
    _short_name = models.CharField(db_column="short_name", max_length = 32, blank=True)
    capital = models.CharField(max_length = 1)
    description = models.TextField(blank=True)
    progress = models.CharField(max_length = 32, blank=True, null=True)

class Relation(models.Model):
    name = models.CharField(max_length = 128)
    _short_name = models.CharField(db_column="short_name", max_length = 32, blank=True)
    description = models.TextField(blank=True)
    parent = models.ForeignKey('self', blank=True, null=True)
    order = models.IntegerField(blank=True, null=True)
    particle = models.ForeignKey(Particle, blank=True, null=True)
    media = models.ForeignKey(Media, blank=True, null=True)

简而言之,模型类 Relation 对其他表有 3 个外键。问题是,当我使用 Django Admin 更改单个关系时,页面 (change_form) 加载速度相当慢。后来,我将模型类 Relation 更改如下:

class Relation(models.Model):
    name = models.CharField(max_length = 128)
    _short_name = models.CharField(db_column="short_name", max_length = 32, blank=True)
    description = models.TextField(blank=True)
    order = models.IntegerField(blank=True, null=True)
    parent_id = models.IntegerField(blank=True, null=True)
    particle_id = models.IntegerField(blank=True, null=True)
    media_id = models.IntegerField(blank=True, null=True)

修改将外键更改为 IntegerFields,因此它禁用了 Django ORM 系统中的一些魔法,现在更改表单页面加载速度非常快。我的问题是,“django orm 中的禁用魔法”是什么?什么有可能导致问题?

4

7 回答 7

39

在 admin.py

from django.contrib import admin

class RelationAdmin(admin.ModelAdmin):
       raw_id_fields = ('Media','Particle',)

admin.site.register(Relation, RelationAdmin)

这会在表单中产生一个漂亮的小 UI 元素,并显着提高性能,因为它不必在选择框中加载大量选项。

于 2013-11-26T12:01:39.127 回答
17

这不是 django Orm 的魔力。这是形式的魔法。当您在 Model 中创建外键时,然后在 ModelForm 中创建一个 ModelChoiceField,它具有 ForeignKey Model 的所有选择。并且 django Admin 使用 Form 的所有属性来创建 HTML。所以使用这个代码。

from django import forms
class RelationForm(forms.ModelForm):
    parent = forms.ChoiceField(required=False,
                              choices=Relation.objects.values_list('id', 'name'))
    particle = forms.ChoiceField(required=False,
                              choices=Particle.objects.values_list('id', 'content'))
    media = forms.ChoiceField(required=False,
                              choices=Media.objects.values_list('id', 'name'))

    class Meta:
        model = Relation 

在 Admis 网站

from django.contrib import admin
class RelationAdmin(admin.ModelAdmin):
    form = RelationForm
    model = Relation

您还可以在表单中缓存选择传递。

于 2013-05-26T07:26:32.170 回答
11

我敢打赌这个问题是由于你的ForeignKey。默认情况下,django<select>为每个外键呈现一个元素。

如果您有数千行,这很容易使您的 HTML / DOM 膨胀,并且我注意到浏览器开始在<select>标签中呈现 20k 个项目时出现问题。

要修复它,请考虑覆盖您的管理表单而不使用默认小部件。

于 2013-05-26T05:32:08.240 回答
1

另一种可能:

正如本页其他地方的@yuji-tomita-tomita 所提到的,管理员为字段change_form呈现了一个<select>元素。ForeignKey

这是使用Select 小部件完成的。

默认情况下,元素中的每个<option>都有<select>一个文本标签,该标签基于指向__str__()的模型的方法。ForeignKey这可以在源代码中看到forms.models.ModelChoiceField

因此,如果您的Model.__str__()方法使用相关字段,当管理表单填充选择选项时,您将获得额外的数据库查询。

例如,基于 OP,假设我们会这样:

class Particle(models.Model):
    ...
    owner = models.ForeignKey(Collection, on_delete=models.CASCADE)
    ...

    def __str__(self):
        return 'particle owned by {}'.format(self.owner.name)

然后管理员需要查询数据库以获取每个选项的相关Collection.name值。Particle

管理员没有有效地做到这一点。

如果你有很多Particle对象,那很快就会变得非常昂贵。

于 2020-08-04T21:06:26.003 回答
1

在我的情况下,缓慢主要是由过时的django-debug-toolbar(v1.7)引起的。debug_toolbar.middleware.DebugToolbarMiddleware如果管理页面包含一个包含数百个选项的 ForeignKey 字段,它将导致管理页面实际上需要 20 分钟才能加载。将工具栏升级到 v1.8 解决了所有问题。也许这对某人有帮助。

于 2017-10-21T18:11:48.903 回答
0

如果 ForeignKey 模型有太多记录,它可能会冻结您的编辑表单。最好的开始方法是限制应该在表单上显示的字段并逐渐/一个接一个地添加其他字段,检查哪个字段使表单变慢。

from django.contrib import admin
class RelationAdmin(admin.ModelAdmin):
       fields = ('name',)
admin.site.register(Relation, RelationAdmin)

然后在添加导致问题的字段后,例如媒体,表单将再次冻结。因此,如果您仍然需要表单上的此字段,您可以使用 Vishal Shah 的回答与 raw_id_fields = ('Media', )

于 2015-09-01T16:18:50.003 回答
0

Django 现在支持使用 Select2 进行输入的autocomplete_fields 。您可以进行如下配置:

from django.contrib import admin

class RelationAdmin(admin.ModelAdmin):
       autocomplete_fields = ('Media','Particle',)

admin.site.register(Relation, RelationAdmin)
于 2021-11-27T02:06:24.443 回答