PyCon Day 0: Delving into the Django Admin
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
orfilter_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