我的一个模特特别复杂。当我尝试在Django Admin中编辑它时,它会执行1042次查询并需要9秒以上的时间来处理。
我知道我可以用raw_id_fields
取代一些下拉列表,但我认为更大的瓶颈是它没有按预期执行select_related()
。
我可以让管理网站这样做吗?
答案 0 :(得分:30)
虽然jimbob博士的回答是有道理的,但根据我的需要,我能够简单地用一行代替覆盖get_queryset()方法,甚至可以选择外键的外键。也许这对某人有帮助。
class MyModelAdmin(admin.ModelAdmin):
model = MyModel
...
def get_queryset(self, request):
return super(MyModelAdmin, self).get_queryset(request).select_related(
'foreign_key1', 'foreign_key2__fk2_foreign_key')
答案 1 :(得分:19)
你可以试试这个
def spreadsheet
spreadsheet = GenerateSpreadsheet.generate(params[:id])
send_file spreadsheet
end
答案 2 :(得分:11)
对于我的特定模型,当它们以表格形式显示时,特别慢的方面是通过ForeignKeys,而不是使用select_related
调用,所以这是我要加速的部分。
查看相关的django来源,您会在django/contrib/admin/options.py
中看到方法formfield_for_foreignkeys
获取每个FK db_field
并调用ForeignKey
类的formfield
方法,在django / db / models / fields / related / like中定义:
def formfield(self, **kwargs):
db = kwargs.pop('using', None)
defaults = {
'form_class': forms.ModelChoiceField,
'queryset': self.rel.to._default_manager.using(db).complex_filter(self.rel.limit_choices_to),
'to_field_name': self.rel.field_name,
}
defaults.update(kwargs)
return super(ForeignKey, self).formfield(**defaults)
由此我们看到,如果我们为db_field
提供kwargs['queryset']
,我们可以定义一个将使用select_related的自定义查询集(这可以由formfield_for_foreignkey
提供)。
基本上我们要做的是用admin.ModelAdmin
覆盖SelectRelatedModelAdmin
,然后创建我的ModelAdmin子类SelectRelatedModelAdmin
而不是admin.ModelAdmin
class SelectRelatedModelAdmin(admin.ModelAdmin):
def formfield_for_foreignkey(self, db_field, request, **kwargs):
if 'queryset' in kwargs:
kwargs['queryset'] = kwargs['queryset'].select_related()
else:
db = kwargs.pop('using', None)
kwargs['queryset'] = db_field.rel.to._default_manager.using(db).complex_filter(db_field.rel.limit_choices_to).select_related()
return super(SelectRelatedModelAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
此代码示例不包括admin Inline
或ManyToManyField
s,或readonly_fields
调用的函数中的foreign_key遍历或自定义select_related查询,但类似的方法应适用于那些例。
答案 3 :(得分:5)
在Django 2.0+中,提高ForeignKey和ManyToMany关系性能的一个好方法是使用autocomplete fields。
这些字段不显示所有相关对象,因此加载的查询次数更少。
答案 4 :(得分:2)
为了完整起见,我想添加另一个最适合我的用例的选项。
正如其他人所指出的,问题通常是加载选择框的数据。 list_select_related
在这种情况下没有帮助。
如果您实际上不想通过管理员编辑外键字段,最简单的解决方法是将相应字段设为只读:
class Foo(admin.ModelAdmin):
readonly_fields = ('foreign_key_field1','foreign_key_field2',)
您仍然可以显示这些字段,只是没有选择框,因此 Django 不需要从数据库中检索所有选择框选项。
答案 5 :(得分:1)
对于管理员编辑/更改特定项目的页面,外键选择框可能需要花费很长时间才能加载,从而改变django查询数据以获取外键的方式:
Django docs on Using formfield_for_foreignkey
假设我的foo
模型上有一个名为Example
的字段,我希望选择相关的bar
对象:
class ExampleAdmin(admin.ModelAdmin):
def formfield_for_foreignkey(self, db_field, request, **kwargs):
if db_field.name == "foo":
kwargs["queryset"] = MachineTool.objects.select_related('bar')
return super().formfield_for_foreignkey(db_field, request, **kwargs)