Upgrade to Pro — share decks privately, control downloads, hide ads and more …

But, Why is the Admin Slow?

Sponsored · SiteGround - Reliable hosting with speed, security, and support you can count on.
Avatar for Jacinda Shelly Jacinda Shelly
September 08, 2015

But, Why is the Admin Slow?

DjangoCon 2015 Talk

Avatar for Jacinda Shelly

Jacinda Shelly

September 08, 2015
Tweet

More Decks by Jacinda Shelly

Other Decks in Technology

Transcript

  1. ABOUT ME • Platform Engineer at Doctor On Demand •

    Been using Django for 4+ years • Given two tutorials on the admin • Second time speaking at DjangoCon • Love reading and rowing
  2. class LibraryUser(AbstractUser): ''' Custom user for our library project. Inherits

    from AbstractUser, which has the following fields: - username - first_name - last_name - email - is_staff - is_active - date_joined ''' birthdate = models.DateField('Date of Birth', null=True, blank=False) gender = models.CharField('Gender', max_length=1, choices=GENDER_CHOICES, blank=False) books = models.ManyToManyField('stacks.Book', through='stacks.LoanedBook') def __unicode__(self): return self.get_full_name()
  3. class Book(AbstractItem): authors = models.ManyToManyField(Author, related_name='works') page_count = models.PositiveIntegerField() title

    = models.CharField(max_length=4000) daily_fine = models.DecimalField( max_digits=4, decimal_places=2, default='0.25', help_text=_("Amount the patron will be fined per day for an overdue library book")) def __unicode__(self): return self.title
  4. class LoanedBook(models.Model): patron = models.ForeignKey(settings.AUTH_USER_MODEL) book = models.ForeignKey(Book) checkout_date =

    models.DateField() due_date = models.DateField() return_date = models.DateField(null=True, blank=True) times_renewed = models.IntegerField(default=0) fine_paid = models.NullBooleanField() def __unicode__(self): return ': '.join([str(self.patron), str(self.book)])
  5. def __unicode__(self): return ': '.join([str(self.patron), str(self.book)]) Problem: Solution 1: @admin.register(LoanedBook)

    class LoanedBookAdmin(admin.ModelAdmin): list_display = ('patron', 'book') Solution 2a: @admin.register(LoanedBook) class LoanedBookAdmin(admin.ModelAdmin): list_select_related = True Solution 2b: @admin.register(LoanedBook) class LoanedBookAdmin(admin.ModelAdmin): list_select_related = ('patron', 'book')
  6. @admin.register(LoanedBook) class LoanedBookAdmin(admin.ModelAdmin): list_select_related = ('patron', 'book') def get_queryset(self, request):

    qs = super(LoanedBookAdmin, self).get_queryset(request) qs = qs.only('patron__first_name', ‘patron__last_name', 'book__daily_fine') return qs Well, let’s see…
  7. @admin.register(LoanedBook) class LoanedBookAdmin(admin.ModelAdmin): list_select_related = ('patron', 'book') def get_queryset(self, request):

    qs = super(LoanedBookAdmin, self).get_queryset(request) qs = qs.only('patron__first_name', ‘patron__last_name', 'book__title') return qs Fixed!
  8. Now, we want to try something else # models.py class

    Book(AbstractItem): authors = models.ManyToManyField(Author, related_name='works') def authors_display(self): return '; '.join([str(author) for author in self.authors.all()]) # admin.py @admin.register(Book) class BookAdmin(admin.ModelAdmin): list_display = ('__unicode__', 'authors_display') list_select_related = True
  9. Solution @admin.register(Book) class BookAdmin(admin.ModelAdmin): list_display = ('__unicode__', 'authors_display') def get_queryset(self,

    request): qs = super(BookAdmin, self).get_queryset(request) qs = qs.prefetch_related('authors') return qs
  10. Next Up - Counting! # models.py class Author(models.Model): def book_count(self):

    return self.works.count() # admin.py @admin.register(Author) class AuthorAdmin(admin.ModelAdmin): fields = ('first_name', 'last_name') list_display = ('__unicode__', 'book_count')
  11. Custom Querysets to the Rescue (again)! from django.db.models import Count

    @admin.register(Author) class AuthorAdmin(admin.ModelAdmin): fields = ('first_name', 'last_name') list_display = ('__unicode__', 'book_count') def get_queryset(self, request): qs = super(AuthorAdmin, self).get_queryset(request) qs = qs.annotate(book_count=Count('works')) return qs