with Jacinda Shelly

The Django admin interface has always been considered by the Python community to be the “killer app” that draws users to Django. And for good reason. MVC software design is an excellent model, but writing the ‘V’iew part of the trio is a real pain in the butt; especially when there are a pretty limited number of types that are available in the database backend. It really makes sense to have a library of webUI elements that correspond to each of the database types.

This is exactly what the Django admin interface gives you for free when you define your model. You write like one or two lines of code, and you get a set of web pages that let you add input to your database, and do type checking, input validation and everything else for free. It’s pretty sweet.

I’ve had good luck using the Django admin interface for my personal project of keeping track of my vast collection of GPS tracks from running/biking/hiking. I have a little Django application that lets me edit a few attributes of my tracks and write descriptions of them.

Unfortunately, I’ve never found a good way to utilize it for work at PCIC. So much of our data is bulk data that comes from sources other than manual entry that it doesn’t seem like a good fit. On the other hand, there are a few applications that I can think of where it might be helpful:

  • editing metadata (station locations, station histories, network managers and contacts, etc.) for the CRMP meteorological stations
  • managing the complex chain of relationships in our modelmeta database, particularly those which control what data gets published and on what pages

To evaluate whether these applications might be possible, it’d be good to learn in more depth about what is possible with the Django admin app.

Goals

The goals and purposes for the tutorial were to go beyond the stock, default layout and setup of the Django admin interface. The default admin interface is powerful enough, and with a little bit of customization, subclassing, method overriding, you can pretty much avoid writing any UI code for administering your objects.

GitHub repo for the tutorial is here.

Overriding Templates

Override the Django Admin template

You can override the templates on your own by writing your own templates. But it’s much easier to just set a couple attributes in urls.admin.site

AbstractUsers

Subclass AbstractUser, add a couple fields, and then subclass that to have specialized users.

You could just hang profiles off of the user, but it’s up to you. If it’s going to make your life easier to subclass it, then you can.

Overriding UserAdmin.get_fieldsets()

If you parent class does most of what you want it to do, then rather than explicitly declaring all of the fields to include in the admin, use get_fieldset() with super() and then add the custom fields

One interesting thing that you can do with overriding methods, get_fieldset() actually takes an optional parameter obj which defaults to None. But you can use that to return only a select few of the fields that need to get a user up and running. So… use super() instead of steamrolling get_fieldsets() and returning everything.

fields is one of the most basic ways to override it for customization. fieldsets groups things together nicely. If you want most, but not all, you can use exclude. But explicitly specifying is probably better practice.

Stacks

AbstractItem

Doesn’t get instantiated directly:

  • you would subclass it to create a book and add unique fields to books
  • subclass to a DVD and add unique fields… etc.

LoanedBook is the many-to-many through model mapping users to books (users can checkout many books and a book can be checked out by many users (over time))

Used a package called fake-factory to create fake data for books and authors. Find it in the scripts directory.

Add help text to stacks.models.py so new users to the admin can actually see what fields are supposed to mean. Makes onboarding easier. Makes things more self-explanatory.

  • filter_horizontal or filter_vertical provides a widget that gives you a multiselect with options on one side and your selection on the other
  • There exist other widgets that give you an autocomplete search box

Performance

  • Sometimes you’ll see repeat queries, because Django has to lookup one thing, and then to display that thing it has to go fetch all of the related objects, their attributes, and not cache them.
  • Complex relationships can have a multiplicative affect

    • I have seen list queries run thousands of queries and peg the CPU on the database server
    • Solution? list_select_related = True class attribute. This is kind of the sledgehammer method
    • alternative: list_select_related = ('the_one_related_object_you_want')
    • Caveat: if you have a lot of interconnected models, it will follow the joins which may not be what you want
  • You can specify an only field that lets you only select certain fields rather than everything.

Randoms

  • Look for the Django Admin Reference docs which shows you everything that you can customize.
  • When do you want to roll your own? When your users are not actually using it to manage the data.
  • “Inlines” (TabularInline and StackedInline),
  • Can add methods, and tell Django whether they are boolean… is_boolean flag.

    • Sometimes when you do the customizations, you have to add certain features back in (e.g. localization on the dates, sorting of the dates)
  • django-debug-toolbar is awesome. Use it.
  • You can turn off counting if database counts take a long time
  • Can set read only fields with get_readonly_fields(self, request, obj=None)

Final thoughts

Multiple times, Jacinda said “There is no magic in the Django Admin app. It’s just another Django app.”. Meaning it’s pretty straightforward and behaves in the same ways that other apps do. Given that, customization is typically pretty straightforward and can be accomplished with just a couple lines of code.



blog comments powered by Disqus

Published

08 April 2015

Category

work

Tags