We're sorry but this page doesn't work properly without JavaScript enabled. Please enable it to continue.
Feedback

Saved you a click (or three): Supercharging the Django admin with actions and views

00:00

Formal Metadata

Title
Saved you a click (or three): Supercharging the Django admin with actions and views
Title of Series
Part Number
13
Number of Parts
48
Author
Contributors
License
CC Attribution - ShareAlike 3.0 Unported:
You are free to use, adapt and copy, distribute and transmit the work or content in adapted or unchanged form for any legal and non-commercial purpose as long as the work is attributed to the author in the manner specified by the author or licensor and the work or content is shared also in adapted form only under the conditions of this
Identifiers
Publisher
Release Date
Language

Content Metadata

Subject Area
Genre
6
Thumbnail
42:19
Group actionView (database)Staff (military)Event horizonMaxima and minimaContent management systemContent (media)HypermediaDigital signalTemplate (C++)Computer fontMathematicsLine (geometry)Endliche ModelltheorieWebsiteData modelAsynchronous Transfer ModeFile formatHyperlinkField (computer science)System callLink (knot theory)Electronic mailing listMultiplication signSymbol tableHyperlinkTelecommunicationError messageView (database)Field (computer science)Cheat <Computerspiel>Canadian Mathematical SocietyLibrary (computing)InformationCASE <Informatik>Coefficient of determinationDigital photographyLevel (video gaming)Open setMereologySoftware frameworkEvent horizonFile formatPoint (geometry)Greatest elementEntire functionRight angleQuicksortInstance (computer science)Physical systemData structureEndliche ModelltheorieComputing platformBitHacker (term)Moment (mathematics)Chemical equationObservational studyContent (media)Pairwise comparisonInheritance (object-oriented programming)Euler anglesBlogUniform resource locatorMathematicsIterationProcedural programmingLanding pageData modelSet (mathematics)Limit (category theory)WebsiteWindowSeries (mathematics)Computer filePattern languageKernel (computing)DatabaseHypermediaMultiplicationWordSystem administratorGroup actionPasswordTemplate (C++)Object (grammar)LogicComputer configurationElectronic visual displayForm (programming)ChainCodeLoginEmailModule (mathematics)Zoom lensMobile appArrow of timeWeb pageCombinational logicNP-hardDigitizingComputer programmingComputer animationProgram flowchart
Group actionData modelQuery languageDynamic random-access memoryRadiusComputer fontView (database)MathematicsInstance (computer science)Line (geometry)Asynchronous Transfer ModeGroup actionAsynchronous Transfer ModePoint (geometry)Axiom of choiceField (computer science)Boolean algebraCoefficient of determinationEndliche ModelltheorieText editorInstance (computer science)Graph (mathematics)CASE <Informatik>Canadian Mathematical SocietyBitReplication (computing)Row (database)Electronic mailing listLibrary (computing)MathematicsChainObject (grammar)MereologyFunctional (mathematics)Directed graphRight angleMessage passingGoodness of fitHyperlinkEquivalence relationLink (knot theory)View (database)AreaGame controllerQuicksortCombinational logicSystem administratorLine (geometry)Conformal mapCountingEvent horizonProcess (computing)File formatData miningSinc functionInteractive televisionGenderDatabase normalizationMultiplication signWeb 2.0Order (biology)Template (C++)CuboidElectronic visual displayCodeIncidence algebraState of matterDifferent (Kate Ryan album)Connectivity (graph theory)Greatest elementQuery languageFront and back endsUniform resource locatorSynchronizationWebsiteSet (mathematics)Zoom lensAttribute grammar
Group actionView (database)Pointer (computer programming)InformationIRIS-TMenu (computing)Insertion lossMaxima and minimaRandom numberObject (grammar)Query languageUniform resource locatorAsynchronous Transfer ModeMeta elementData modelRaw image formatSoftware frameworkRouter (computing)DisintegrationWebsiteContext awarenessMereologyOpen sourceEmailDemo (music)Demo (music)Functional (mathematics)Flow separationSoftware frameworkEndliche ModelltheorieField (computer science)View (database)QuicksortContext awarenessData managementSystem callSet (mathematics)Router (computing)Library (computing)Bit rateGroup actionService (economics)CASE <Informatik>WebsiteClient (computing)System administratorInstance (computer science)BuildingCoefficient of determinationWave packetLine (geometry)BitDampingCodeCombinational logicDisk read-and-write headPhysical systemWordGenderFreezingDirection (geometry)MereologyStandard deviationReverse engineeringUniform resource locatorCodeWeb pageDependent and independent variablesOpen setSerial portFeedbackMathematicsLink (knot theory)Repository (publishing)State of matterPower (physics)Pattern languageINTEGRALAlgorithmInformationAsynchronous Transfer ModeModule (mathematics)DebuggerMultiplication signDifferent (Kate Ryan album)Canadian Mathematical SocietyComputer animation
XML
Transcript: English(auto-generated)
I'm going to be talking about actions and views in the Django admin. Mostly, a lot of this is we're talking about some easy ways
to customize it to get people some quick information. The joke is to save you a click. This is saving our admin users a click. So especially, we're going to start talking with a lot of tips and tricks in libraries. It might be an overload at first. It's going to go from a beginner level,
and then we're going to kind of abstract it out and talk a little more abstract at the end. But the point is that there's a lot of ways to do this, to do some of the things that we need to do with the admin. There are a lot of libraries that kind of overlap and conflict that are all kind of on the same page. So the conclusion isn't necessarily, part of it is to give you guys some tools and ideas and tricks. But part of it is also to sort of suggest other ways
to think about the admin more holistically and provide a framework for it. And also, I thought this talk was 45 minutes, so that's another reason it's going to be overlooked, because I'm going to be going a little faster than I expected. A lot of this is, I've learned a lot of this by doing work at the Texas Tribune. I've been there for about two years. The Texas Tribune is based in Austin.
We're a nonprofit, nonpartisan, all digital news organization. We focus on Texas politics and policy. We have a combination of news, data, and events. We also have two of my colleagues, Annie and Ty, are also here, who focus on these things as well. We'd love to talk to you more. But the idea is basically, we have a lot of users.
Our CMS users are very busy, strapped for time. They need to publish breaking news very fast. But then we also do a lot of investigative features and longer stories where we want well-structured data, where we can make sure that it gets presented well all the time and on every platform that we're on. So it's a tough balance, and we do it all with Django.
It's all pretty much vanilla Django right now. We're looking at moving towards a CMS framework like Django CMS. But at the moment, yeah, it's all pretty much vanilla. So we have found a lot of little tips and hacks and things that you can do in that vanilla Django admin to make it really fast and easy for users to publish stories.
A little bit about my background. I've been at the Tribune for two years. Before that, I was in a program called Comparative Media Studies at MIT, working in the Hyperstudio's Digital Humanities Lab. And before that, I was working at a news curation startup called Wiser. I was battling the Django admin there as well. But I feel like it really stretched its limits
in the last couple of years at the Tribune. We found that, especially when I first started with Django, when I was working with it, I really quickly wanted to add a couple of easy buttons here and there. Quick actions, quick views, just little stuff that shouldn't be that hard. And every time, I had a sad time.
And it ended up with a lot of coupled files, a lot of coupled code. It just never felt right to me. I struggled with it a lot. But at the Tribune, we recently completed an admin redesign a little bit on just reskinning of our admin. And I learned a lot. It gave us an opportunity to re-architect some of the ways that we're doing some of the admin
customizations. So if you think of the admin, the Django admin as a series of windows that are increasingly getting into a kernel of information you need, you start with the whole dashboard site, the whole site. Then you move into a list view. And then you move into a detail view. And then you move into inlines inside of that. I'm going to use that zooming in as a framework for some
of the tricks I'm going to talk about in this talk. Then at the end, I'm going to try to wrap it all up into a bow and talk about why they all have similar patterns that we can learn from. So yeah, again, part of the intention is not intention, but it might overwhelm. And it will be a lot, but hopefully
it'll make some sense at the end. I'm throwing a lot against the wall. I want to see what sticks. We're going to be using an example site. It's called Newshound. It's a blog by dogs, for dogs, and about dogs. And it also has a database of breeds, dog breeds, which were scraped from the American Kennel Club the other day.
So you can follow along at GitHub, github.com slash mail backwards slash Newshound. There are going to be examples there of everything I'm about to show. So hopefully it won't be quite as overwhelming. And I apologize in advance. They're extremely contrived examples. I ran out of ideas for how to talk about dogs. The data model that we have in Newshound
is basically we have blog posts. And a post might be about individual dogs that you're talking about. Each of these dogs can be part of multiple breeds. And that's a custom through model because a dog can be 25% schnauzer and 75% chihuahua.
And then each breed is part of a breed group. So for instance, the toy group, or the herding dog group, or the terrier group. Again, this is really contrived, but got to start somewhere. So really quickly, I'm going to start with the admin site and landing page. A quick thing that you can do here to make your initial dashboard a little friendlier
is to have a custom admin site on your Django admin. Basically, this has a couple of advantages. First of all, you can customize your site header. So now you'll see over here, if I can get my, yeah, over here. So it says Newshound up here at the top, rather than just a Django administration.
And then it also allows you to do custom login templates. So here I made a custom login, and I just added a forgot your password option down here, which is something that we have on our CMS. So it's really handy to have this custom admin site to make really easy, quick changes. And I also personally like that it puts all of the admin site logic into one module
so you don't have these auto-discovers going on all over and across different apps. You have a centralized place where all of your admin site logic lives. Moving on to the changelist views. This is probably the bulk of it. We have a lot of tricks up our sleeve here. Here's a basic changelist view with just the blog post.
You'll see there's one article that's been published, and it has a great headline. It doesn't give us very much information, though. There aren't a lot of columns here. Not much you can do. So the first thing you can do is add list display to your changelist. This lets you add any other columns you want.
So here you get a second column. Pretty straightforward. Most people know this one. But if you take list display a step further, you can do a few other things. So first of all, you can add extra fields that aren't actually on your model, and then define them in the admin and say what you want the content of the column to be.
So in this case, we're just listing all the dogs that have been tagged or associated with this blog post. If you do this, don't forget to select related or prefetch your related model, because otherwise it will get heavy and slow very fast.
The other thing I'll talk about with list display, one thing we use a lot is to combine it with Django's format HTML. This lets us put any arbitrary HTML into those columns. So in this case, for instance, what we're doing is for each dog, we're making a little hyperlink
to the dog's absolute URL. And it manifests over here. It's kind of hard to see. But you just get this nicely formatted list of names, and then you have a link out to go see those names. The other thing I'll point out here is this is just an HTML entity for an arrow. I think that's a really easy way to do visual communication
rather than overloading somebody with walls of text or a bunch of hyperlinks. Just put little symbols in there. It's just text. It's really easy to do, and it makes it visually cleaner. I'm cheating a little here. I'm going to talk about the detail view really quickly and then go back to the changeless view. But another way that you can use format HTML
is with read-only fields. And read-only fields, very similarly, if you set, in this case, it's a photo preview, if you put it in your fields, it'll show up in the detail view. And you can, again, put any HTML you want in here. So in this case, you're getting a preview of this dog breed. I can't read it.
But it's a cute dog. It gets into your admin. Who wouldn't like that? Back to the list view, another handy trick is list editable. This one here you'll see, it turns this headline field into an open text field that you can just edit from the list view. So if you had 100 of them here, you could edit all 100 at once and then go click the Save button
at the bottom. And you're all set. We find that this one, since it adds another button and it adds a whole bunch of form fields, it's not very friendly to users. I think it stresses people out when they see it. But we actually use it. It's particularly handy for cleanup sprints, which is what we found. So for instance, at the Texas Tribune,
we have a lot of tag data. And some of it's very messy. So there was one sprint where we decided we're going to clean up our tags. And so for those, I made a lot of fields list editable for the time that we were doing this sprint. And that was really helpful for just getting in there really quickly, making the big alterations, and then saving.
Then you're done. And moving on from displays to actions. Actions, at their most basic level, admin actions allow you to basically check off certain items in that change list in the checkboxes and then perform a function based on what you've checked off.
In this case, this code is publishing all of the checked off items that you had. It might set them all to be published. One thing we've started to do at the Tribune is make dynamic actions based on some of the choices that are in our models. So in this case, we have a few different states for publication. You might have it in draft mode,
in edit mode, in published mode. And here, this code is basically just making an action for each of those states. And then it manifests in the end with this list at the bottom of actions. You can set it to draft, set it to publish, set it to edit. And it will just change based on the models. Zooming out even farther, this is really tiny code.
I'm sorry. But even farther, we've started working on admin mixins or action mixins. In this case, what it's doing is basically defining. What you can do is define an action fields attribute on your admin model. And at that point, it will add those action choices for you.
So in this case, that works for either a Boolean field or for choices. So here, for instance, we have a post admin, which is setting it to either draft, edit, or published. And then down here, it's hard to read. But you also have a dog admin. Dogs have a Boolean attribute for whether they're good or not.
And in this case, you can set the attribute to be. You can set all of these checked items to be. All of them could be good, all of them could be bad. And it's just done with this nice handy mixin, so you don't have to worry about replicability. Moving a little bit more into the libraries and packages that we might talk about.
What if you want to add actions, for instance, for each item in your changelist? You have your list of items, and you just want your button next at the end of each of them to do something with that individual item. This is a really handy package called Django Admin Row Actions. And it basically adds that column for you
down here in the corner. You'll see it has this dropdown called Actions. You click on it. In this case, you can either redirect to the delete view for that individual object, or you can make all the dogs good, I guess, in this one. So it's usually defining a particular action or a particular URL.
And then it will do the rest for you. Another package that we use a lot is called Django Object Actions. This was developed, actually, at the Texas Tribune by our old colleague, Chris Chang. It does a whole lot for us. This is one thing it does.
Basically, it lets you easily put buttons in the changelist without modifying your template. So you'll see down here, you have this Publish All Edits button that just shows up here in the corner on this changelist view. And it's really just defining any other function here. And the one key part is this changeless actions part. And that's all it takes to add a button right there,
which we actually found was harder than it should have been to do sustainably. One way that we use these buttons for our models is we often sync our models with external APIs. So for instance, we sync with MailChimp or Eventbrite, and that's where we store a lot of our data for our events.
So we might put a Sync button right there so that people can quickly just sync up our CMS and our website with whatever's going on externally. And it's a pretty easy place to put it. Zooming further into the change views, again, with Django Object Actions, they have not just changelist actions.
They also have change actions. And these are even handier, I think. So in this case, this just lets you take that particular instance and use that rather than having it be list wide. Here, we are making all the dogs good in this particular article. So this article might have mentioned a few dogs. They're all automatically good if you click this button.
And also, it maintains a lot of the admin features like message user. You can do a lot of the same functionality that you could do with any view, any admin feature. And I want to reiterate, redirects make it really easy to add hyperlinks or the equivalent of hyperlinks without changing your template models.
So in this case, this is basically a link. It's just you're going to a certain changeless view. But you're doing it with actions. And that just moves it further into the back end and lets you control it more. I also really like this handy takes instance or query set decorator that comes from Django Object Actions, which lets you put it
on both the change and the changeless view at once. So that's a handy feature. And a shout out to Chris if you're here. Because actions are just views under the hood, you can add confirm views, confirmation views, kind of like the Django delete view for resources.
This is kind of a combination of the two things, the two sort of the action and the reader or the link. So in this case, stepping through with this publish edited action is doing. You start with, so the first thing you do is it looks for a post request.
It doesn't see one. So it just renders a confirmation view. And here's the confirmation view over here. It just makes sure that you want to delete these things. The second time around, if you put all you have to do, and it's really tiny text, but all you have to do is put an action value into the post data.
And it will send it straight back to this view. So you can use the same view to both render the confirmation view and also process the confirmation when it happens. In this way, you get the best of both worlds. And it's all wrapped into one nice little function. Zooming further into inlines, we
have a couple other packages that we have found really handy here. The first one here is just a generic inline that says no edits. This is showing a post can have multiple dogs. And you can assign them. Django inline actions is basically,
so earlier we saw Django admin row actions, which lets you change specific items from the change list. This is sort of another layer of inception from that, where you're now able to edit and process things from the inline view, since Django admin row
actions couldn't do that. So in this case, you are, again, just getting a link to redirects to a different resource. It's pretty easy to do. Just for reference, you can also use Django inline actions in the change list.
So this is kind of redundant with Django admin row actions, which I showed earlier. But it's good to know. Another admin feature that looks really handy, we haven't had an opportunity to use it at the Tribune. But I've always been interested in it, is Django nested admin. This is developed by our friends at the Atlantic.
And it's basically inline inception. In this case, you have a breed group. So that might be like toy dogs. And then each breed group has multiple breeds. And then each breed has multiple dogs associated with that breed. This Django nested admin allows
you to put all three of those layers right in one view. So here, you're able to edit everything about the breed group, everything about the breed, or anything about the dogs themselves. It also does sorting for you. That's a really handy feature. If you have orderable fields, you can set it as orderable and then just drag and drop them.
One warning is I would be aware of over-querying without prefetching. And I'm not entirely sure how that works under the hood for Django nested admin, but just to be aware of doing too much with it because your view could get really, really slow. So I'm done with talking about packages for now.
I want to look a little bit at what we could do next, sort of thinking about all of these together, all these different packages and ideas. One thing that I found is that basically all of them are using this get URLs function from the admin. Get URLs is basically from the Django docs. It just shows you can add any additional views to that model
admin on the fly. And it's a really handy idea. It's pretty much how all of these different tools and mixins are working. So we have started to fold more of our admin features
into mixins using get URLs. And specifically, we are interested in how to do this with Ajax views. We want to put a little bit more dynamic information and live updating information into our admin. And we want to be able to do it where it integrates nicely with the Django admin. In this case, I believe this example,
we are putting in a preview of all the dogs that are currently trending. I'm not sure why they're trending. But if you're a writer writing about dogs, you might want to know which dogs are trending so you know who to write about. So in this case, basically, this get URLs function
is just sending anything that goes to the trending URL back to that trending function. And that's where a lot of the work happens. Here, I happen to be using a dog serializer from Django REST framework to actually create the dog response. You could do it in a million different ways. And then the JavaScript, it looks a little long,
but it's really not very complicated. It's just calling an API and updating a container. And this is sort of what it ends up looking like. And so down here, you'll see this is just the changeless view over here. But above it, you get this Ajax-driven little module
that shows you three dogs that might be trending. If you click this button over here that says refresh suggestions, you get three different dogs, or maybe the same dogs if they're still trendy. So this has gotten me thinking. We're using this Ajax view, basically, this JSON view.
And Python and Django has this incredible framework for doing just that, Django REST framework. And I've been thinking about the best ways that we could be combining all the powers of the Django model admins with all the powers of Django REST framework. So here, I changed this to the trending dog view
instead of putting that view on the admin. And then here, I made a new API view that is basically taking what was about a 10-line function and turning it into three lines, and then also getting all the bells and whistles that the REST framework gives you on top of that. So that's a pretty handy pattern that we're interested in.
One step even farther that I've been thinking about, this one is basically moving the trending algorithm into a model manager under the dog model, and then turning this into a full-on view set. So with the right pagination, this functions exactly
the same way as that 10-line view did. So it's all declarative. Now there's no function, really. And that feels like a better separation of concerns to put the trending into the manager as well. So I feel like this is a really promising start to something, but it has no way, for instance, to get into the detail view to receive the context that the model admin gets, at least the way that I set it
up. And this is just to finish that off. This would be the get URLs for this view set. All you need to do is add that trending URL and call that view, and then you're rolling.
So yeah, I think there's something here, and all these libraries are pointing to it, that combining the Django model admin and REST framework is something we're increasingly doing. And we're curious. I feel like it's a very powerful combination and want to do more with it.
Is there a possibility, for instance, of getting full CRUD capability on Django models with Ajax views right in the admin, with all the context and all the richness that the Django admin provides? I think some open questions with that that we aren't sure about. What's the best way to integrate with the router framework?
What are the best ways to integrate, to put the admin context into the API view sets? And what's the best way to manage your front end assets, especially your JavaScript, your CSS, for whatever you're doing with Ajax? But more broadly, this feels like the right step to go.
We want our admin to be an API client, just like our website is, just like our external services are. It feels better architecturally. So we're interested in how to work towards it. But we also don't necessarily want to build a custom whole Django admin, separate admin from scratch, because we just don't have the team for that.
I think some of this is starting to beg the question of why would we stick with the admin at all. And I pointed to that a little bit. And I think one of the short answers is we have an eight-year-old website. And it's a lot of built-up code. And it would be really hard to do that,
to basically offload the whole thing onto a whole new system. But the longer answer is that there's a lot of promise in the Django admin. You get these things like versioning for free using Django reversion. You get things like locking with Django locking. And the standardization in the community around that just opens us up to a lot of really interesting
possibilities, especially with the directions that Django REST framework has been going. So we're excited. We're sticking with the Django admin. We might end up, as I said, we might end up standardizing it further by putting it on something like Django CMS or Wagtail. But we're just excited about the future possibilities on the Django admin.
And we think that there's more that could be done with it. So I wanted to shout out to all of the repositories that are in the packages that we used. Here's links to them on GitHub. And I think I covered them all.
And to reiterate, this is Newshound. And quickly, I'm going to show a demo just in case some of that was hard to see. Here's the dashboard for Newshound. You've got breeds, dogs, posts, and breed groups.
If you go into the post admin, you'll suddenly get those trending dogs. We've got Chubb. Chubb is a very interesting combination of breeds here. These dogs are not real. So I refresh it. Let's refresh it again. Let's just keep looking at dogs for a while.
So down here, I'll show you a couple other features that we have in here. Again, we have that view breeds button. So you can just go quickly see all the breeds. You can publish all your stories that are currently in edit mode. So right now, that's in edit. So if I publish this, I get that confirmed view. And I click, and hey, it's published. And now you see the publication status moved to published.
Here's this editable field here. So if I want to make it dogs, then I hit Save. And it'll update that. If I click in here, you'll again get the same preview. And here, you'll see evidence of the inline action.
So you can see all the breed groups that this dog, Kira, is part of. Kira is a hound. I believe this is where we'll see the inline action. So this is going to, or the nested admin, this is going to load really slowly because I did not pretty much anything. But this is basically where you can edit pretty much the whole admin from one page. So that's why it takes a while.
So all of this, oh, here we go. So here, you have the hound. Here's the first one. You have the Afghan hound. We've got Harley. Harley is 100% Afghan hound. So you can start to change any of these details straight here from the admin. And it's all nested. So the next one down, for instance,
is the American English coonhound. Keep going. So this is a really handy feature. So all of this combined, this is all about, I think, probably about 100, maybe 200 lines of code. And we really got a lot of features in. And it feels like a nice separation of concerns.
And I'm going to stop there because I want time for questions and feedback. We're, again, not really all the way there. We have a lot of open questions, especially around how to integrate this framework. So we want to hear more. Thank you very much.