我的一个Django网站有以下数据库模型: 在Django App中“常见”:
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 App“情景喜剧”中:
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更改单个Relation时,页面(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)
修改将Foreign Keys更改为IntegerFields,因此它禁用了Django ORM系统中的一些魔法,现在更改表单页面加载速度非常快。 我的问题是,什么是“django orm里面的残疾魔法”?什么有可能导致这个问题?
答案 0 :(得分:16)
在admin.py
中from django.contrib import admin
class RelationAdmin(admin.ModelAdmin):
raw_id_fields = ('Media','Particle',)
admin.site.register(Relation, RelationAdmin)
这会在表单中显示一个漂亮的小UI元素,并显着提高性能,因为它不必在选择框中加载大量选项。
答案 1 :(得分:10)
这不是django Orm的魔力。这是Form的魔力。 在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
您还可以在表单中缓存选项传递。
答案 2 :(得分:6)
我愿意打赌这个问题是由你ForeignKey
引起的。默认情况下,django为每个外键呈现<select>
元素。
如果你有成千上万的行,这很容易开始膨胀你的HTML / DOM,我注意到浏览器开始废弃在<select>
标签中呈现的20k项目。
要修复它,请查看覆盖管理表单而不使用默认小部件。
答案 3 :(得分:1)
在我的情况下,缓慢主要是由过时的django-debug-toolbar
(v1.7)引起的。如果管理页面包含一个包含几百个选项的ForeignKey字段,那么debug_toolbar.middleware.DebugToolbarMiddleware
会导致管理页面加载20分钟。将工具栏升级到v1.8解决了所有问题。也许这有助于某人。
答案 4 :(得分:0)
如果ForeignKey模型记录太多,可能会冻结您的编辑表单。 最好的方法是限制应该在表单上显示的字段,逐步/逐个添加其他字段,检查哪个字段使表单变慢。
from django.contrib import admin
class RelationAdmin(admin.ModelAdmin):
fields = ('name',)
admin.site.register(Relation, RelationAdmin)
然后在添加导致问题的字段后,例如媒体,表格会再次冻结。因此,如果您仍然需要表单上的此字段,您可以使用Vishal Shah的答案raw_id_fields =('Media')
答案 5 :(得分:0)
另一种可能性:
如@ yuji-tomita-tomita elsewhere on this page所述,管理员change_form
为<select>
字段呈现ForeignKey
元素。
这是通过Select
widget完成的。
默认情况下,<option>
元素中的每个<select>
都有一个文本标签,该文本标签基于__str__()
所指向的模型的ForeignKey
方法。可以在forms.models.ModelChoiceField
的{{3}}中看到。
因此,如果您的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
对象,那么它们很快就会变得非常昂贵。