django - 防止 Django 模板 base.py 解析内联中所有可能的外键关系
问题描述
我正在尝试在现有的 Django Admin 类上创建内联,但发现页面呈现时间太慢了。我已经确定问题出在 django templates/base.py “resolve”函数或后续渲染函数(Django 2.1)中。在所有情况下,似乎我的所有“跟踪”对象都在为该行中的所有表单加载。
如何通过更改代码来提高此功能的性能?我应该重组 Recording-->Tracklist-->TracklistTrack-->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 函数中打印上下文时,我可以看到我的所有曲目都通过 base.py 解析进行管道传输,大概这就是问题所在。
新的内联看起来像这样:
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)
解决方案
对于任何拖网堆栈溢出的人,我使用 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',)
推荐阅读
- python - 我想删除列表中的 x 但告诉我:x 不在列表中
- angular - 一张表格三页。如何在它们之间传递状态?
- webrtc - TokBox Publisher 未能在合理的时间内发布
- java - 如何在 Spring MVC App 中将 CSS 文件与 JSP 视图连接起来?
- java-time - 如何获得尊重夏令时的区域名称(例如 EDT)
- python - 如何将此输出格式化为数组/可用数据
- java - 阻止杰克逊在请求正文的日期字段中接受数字
- python-3.x - Pandas read_csv 附加一行 Nan 值
- c - 如何将 CRC32 的调节因子计算调整为 CRC16?
- java - 以“0”结尾的浮点值不能用两位小数表示