Я пытаюсь создать Inline для существующего класса администратора Django, но обнаружил, что время отображения страницы слишком медленное. Я обнаружил, что проблема заключалась в функции django templates / base.py «resol» или в последующей функции рендеринга (Django 2.1). Казалось бы, все мои объекты «Track» загружаются для всех форм в строке во всех случаях.
Как я могу увеличить производительность этой функции, изменив мой код? Должен ли я реструктурировать запись -> Tracklist -> TracklistTrack -> Отслеживание отношений? Могу ли я как-то кэшировать объекты моей модели? Использование модели .thth inline неразумно?
Чтобы начать искать проблему, я начал использовать профилировщик. При запуске таймера для кода рассматриваемый профилировщик вызывает незначительное замедление.
Я вижу, что подавляющее большинство моих вызовов функций 22s выглядит следующим образом:
ncalls totaltime percall cumtime percall имя файла: lineno (функция)
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)