我正在开发一个Django项目,该项目已经有大量的实际数据,因此我可以看到其性能。
几个DjangoAdmin列表的性能简直糟透了。
我有一个管理员列表,将其称为devices
。在该列表中,我正在获取每一行的其他信息,这些字段与其他表相关,并通过FK / PK / M2N连接。
列表包含大约500条记录,根据django-debug-toolbar
,该屏幕的加载大约需要6.5秒,这是无法忍受的。
此管理课程
@admin.register(Device)
class DeviceAdmin(admin.ModelAdmin):
list_select_related = True
list_display = ('id', 'name', 'project', 'location', 'machine', 'type', 'last_maintenance_log')
inlines = [CommentInline, TestLogInline]
def project(self, obj):
try:
return Device.objects.get(pk=obj.pk).machine.location.project.project_name
except AttributeError:
return '-'
def location(self, obj):
try:
return Device.objects.get(pk=obj.pk).machine.location.name
except AttributeError:
return '-'
def last_maintenance_log(self, obj):
try:
log = AdminLog.objects.filter(object_id=obj.pk).latest('time')
return '{} | {}'.format(log.time.strftime("%d/%m/%Y, %-I:%M %p"), log.title)
except AttributeError:
return '-'
所有Machine
,Location
和Project
都是数据库中的表。
在django-debug-toolbar
中查询后,我发现了一件可怕的事情。
该屏幕需要 287 sql查询!是的,超过两百个!
有什么我可以做的事情来减少这段时间吗?
编辑:
多亏了Bruno,我删除了Device.objects.get(pk=obj.id)
(因为它确实多余,所以我完全忽略了这一点。
所以我到处都以obj.
为例obj.machine.location.project.project_name
仅此一项就可以将速度和查询数量减少一半,到目前为止还不错。
我可以很容易地将obj
方法和select_related
方法融合在一起。这是我当前的代码,比仅obj
方法差。
def project(self, obj):
try:
Device.objects.select_related('machine__location__project').get(id=obj.pk).machine.location.project.project_name
except AttributeError:
return '-'
在查询中创建了一个不错的INNER JOINs,但是性能比没有使用并仅使用obj.machine.location.project.project_name
我在做什么错了?
EDIT2:
我获得的最佳性能是此代码:
@admin.register(Device)
class DeviceAdmin(admin.ModelAdmin):
list_select_related = True
save_as = True
form = DeviceForm
list_display = ('id', 'name', 'project', 'location', 'machine', 'type', 'last_maintenance_log')
inlines = [CommentInline, TestLogInline]
def project(self, obj):
try:
return obj.machine.location.project.project_name
except AttributeError:
return '-'
def location(self, obj):
try:
return obj.machine.location.name
except AttributeError:
return '-'
def last_maintenance_log(self, obj):
try:
log = AdminLog.objects.filter(object_id=obj.pk).latest('time')
return '{} | {}'.format(log.time.strftime("%d/%m/%Y, %-I:%M %p"), log.title)
except AttributeError:
return '-'
def get_queryset(self, request):
return Device.objects.select_related('machine__location__project').all()
这将其减少到104个查询(从近300个查询),时间减少了50%以上。可以进一步改善吗?
答案 0 :(得分:2)
首先,避免完全无用的查询-这:
console.log(JSON.stringify(currentFlagObject['src']))
由于Device.objects.get(pk=obj.pk)
已经您要查找的obj
实例而变得毫无用处。
然后override your DeviceAdmin.get_queryset
method来正确使用select_related
和prefetch_related
,这样您只需要最少数量的查询。