HenryM
HenryM

Reputation: 5793

Django Admin super slow selecting single record

I have Pick model which when I select a record within Django Admin takes an age (about 20 seconds) to retrieve the record (there are about 70k). However, it is quick when I try and create/save a record. I have added the indexes to try and speed up retrieval but don't really know what I should be doing

class Pick (models.Model):
    team = models.ForeignKey(Team, on_delete=models.CASCADE, null=True, blank=True)
    user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, db_index=True)
    contest_entry=models.ForeignKey(ContestEntry, on_delete=models.CASCADE, db_index=True)
    game_round=models.ForeignKey(GameRound, on_delete=models.CASCADE, db_index=True)

    objects = DataFrameManager()

    def __str__(self):
        return f'%s %s' % (self.contest_entry, self.game_round)

    class Meta:
        unique_together = ['user', 'contest_entry', 'game_round']
        ordering = ['contest_entry','game_round','user','team']
        index_together = [["user", "contest_entry", 'game_round'],]
        indexes = [
            models.Index(fields=['user', 'contest_entry', 'game_round']),
            models.Index(fields=['game_round'], name='game_round_idx'),
            models.Index(fields=['contest_entry'], name='contest_entry_idx'),
        ]

class PickAdmin(admin.ModelAdmin):
    model = Pick
    list_filter= (
        ('user', RelatedDropdownFilter),
        ('contest_entry__contest', RelatedDropdownFilter),
        ('game_round', RelatedDropdownFilter)
    )

    def get_queryset(self, request):
        return super().get_queryset(request).select_related('user','contest_entry','game_round')
admin.site.register(Pick, PickAdmin)

How can I improve performance here?

Upvotes: 5

Views: 1750

Answers (3)

bdoubleu
bdoubleu

Reputation: 6107

The key is specifying the raw_id_fields on the admin class. The default <select> widget for foreign key relationships can cause a lot of overhead retrieving and rendering all the options.

class PickAdmin(admin.ModelAdmin):
    model = Pick
    list_filter= (
        ('user', RelatedDropdownFilter),
        ('contest_entry__contest', RelatedDropdownFilter),
        ('game_round', RelatedDropdownFilter)
    )
    raw_id_fields = ('user', 'contest_entry', 'game_round',)

    def get_queryset(self, request):
        return super().get_queryset(request).select_related('user','contest_entry','game_round')

Upvotes: 5

hendrikschneider
hendrikschneider

Reputation: 1846

You can improve the queries by using select_related for foreignkeys https://docs.djangoproject.com/en/2.2/ref/models/querysets/#select-related

Upvotes: 0

Daniel Hepper
Daniel Hepper

Reputation: 29977

My guess is that what takes so long is rendering the dropdowns for the ForeignKey fields of your model.

I'd suggest looking at the SQL queries that are performed, either by installing Django toolbar or enabling logging in your database server.

Upvotes: 1

Related Questions