我试图在现有的Django Admin类上创建内联,但是发现页面渲染时间太慢。我已经确定问题出在django templates / base.py“解决”函数或后续的渲染函数(Django 2.1)中。在所有情况下,似乎都为该行中的所有表单加载了我的所有“ Track”对象。
如何通过更改代码来提高此功能的性能?我应该重组“记录”->“跟踪列表”->“跟踪列表跟踪”->“跟踪”关系吗?我可以某种方式缓存我的模型对象吗?内联使用.through模型是不明智的吗?
要开始发现问题,我开始使用探查器。在代码上运行计时器时,有问题的探查器的速度降低幅度可以忽略不计。
我可以看到我的22s函数调用中的绝大多数如下:
ncalls tottime percall cumtime percall filename:lineno(function)
123 0.001 0.000 18.194 0.148 django/forms/widgets.py:232(_render)
123 0.002 0.000 18.190 0.148 django/forms/renderers.py:29(render)
848104 1.037 0.000 3.867 0.000 django/template/base.py:668(resolve)
我查看了堆栈溢出的帖子,这些帖子建议覆盖“ queryset”和“ formfield_for_db”。在django函数中打印上下文时,我可以看到我的所有Tracks都通过base.py resolve传递,大概是问题所在。
新的内联看起来像这样:
model = Tracklist.tracks.through
readonly_fields = ('tracklist', 'recording')
fields = ('track', 'timestamp', 'order')
@silk_profile(name='Slow Inline')
def formfield_for_dbfield(self, db_field, **kwargs):
formfield = super(TracklistInline, self).formfield_for_dbfield(db_field, **kwargs)
if db_field.name in ['track', 'tracklist', 'recording']:
# dirty trick so queryset is evaluated and cached in .choices
formfield.choices = formfield.choices
return formfield
def queryset(self, request):
return super(MyAdmin, self).queryset(request).select_related(
'track').select_related('tracklist').select_related('recording')```
Where Tracklist looks like this:
```class Tracklist(Timestamped, models.Model):
"""Tracklist is a collection of tracks, owned by a recording
1 0...1
Recording ------------------- Tracklist
1 0...*
Tracklist ------------------- Track"""
tracks = models.ManyToManyField(
Track, through="TracklistTrack", blank=True)
recording = models.OneToOneField(
Recording, related_name='tracklist', null=True, blank=True,
on_delete=models.CASCADE)```
and tracklist_track, my customised join table, looks like this:
```class TracklistTrack(models.Model):
"""Stores ordering for a Tracklist/Track relationship"""
class Meta:
indexes = [
models.Index(fields=['recording']),
]
tracklist = models.ForeignKey(Tracklist, on_delete=models.CASCADE)
recording = models.ForeignKey(
Recording, related_name='tracklistsTrack',
null=True, blank=True, on_delete=models.CASCADE)
track = models.ForeignKey(Track, on_delete=models.CASCADE)
timestamp = models.IntegerField(blank=True, null=True)
order = models.IntegerField(blank=True, null=True)```
(A Track is a simple model with two charfields only, but a Recording is a bit of a monster)
答案 0 :(得分:0)
对于任何拖曳堆栈溢出的人,我可以使用django 2.0的自动完成字段非常简单地解决此问题:
class TracklistInline(admin.TabularInline):
model = Tracklist.tracks.through
list_display = ('recording', 'timestamp', 'order')
autocomplete_fields = ('track',)
exclude = ('tracklist',)
extra = 0
@admin.register(Track)
class TrackAdmin(admin.ModelAdmin):
form = TrackForm
ordering = ['title']
search_fields = ('artist', 'title')
list_display = ('artist', 'title',)
exclude = ('modified',)