ProBo: 240.000+ Django Admin Staff Users in a one SaaS

This video features Erik Guldager Laustsen and Johan Valentini Jensen at DjangoCon Europe 2024 in Vigo, Spain.

ProBo: 240.000+ Django Admin Staff Users in a one SaaS
0:27:04
Published July 11, 2024
411 views

Talk: ProBo: 240.000+ Django Admin Staff Users in a one SaaS (What you are not supposed to do, we did it!) by Erik Guldager Laustsen and Johan Valentini Jensen

https://pretalx.evolutio.pt/djangocon-europe-2024/talk/87BXRT/

Summary

ProBo built a Danish property-administration SaaS largely on top of Django Admin, growing from a small customer base to more than 240,000 staff users with a very small development team. The speakers explain that Django Admin provided CRUD screens, permissions, filtering, search, pagination, and change-list behavior quickly enough to meet a tight delivery schedule, while custom querysets and groups handled community- and portfolio-level access. They extended the admin by reusing its internals and templates, adding HTMX-driven active change lists, infinite scrolling, global search, safer inline editing, and a redesigned accessible frontend with web components and lightweight JavaScript. Their central argument is that Django Admin is more extensible than its documentation and common advice suggest, provided developers are willing to read its source code and work closely with its implementation.

Key takeaways

  • Django Admin let a very small team deliver many CRUD-heavy modules within a nine- to ten-month deadline.
  • Django auth groups and custom querysets provided most of ProBo’s multi-community and portfolio-level permissions.
  • Existing admin internals power active change lists, filtering, searching, ordering, pagination, infinite scrolling, and global search.
  • The frontend retained much of Django Admin’s HTML and behavior while adding HTMX, web components, accessibility improvements, and custom styling.
  • The speakers argue that understanding Django Admin’s source code reveals reusable functionality that is difficult to see from the documentation alone.

Summarised automatically from the transcript.

Transcript

4,699 words · auto-generated Show

Automatically transcribed, so expect mistakes in names and technical terms.

0:00

Speaker 1: Hello everybody. We're super psyched to be here. Um yeah, I'd like to just say we changed the title a little bit because we're so close to two hundred and fifty thousand and it just looks a lot better than the two forty that it's originally said. Um yeah um We are do doing a Danish uh Prop Tech SAS application for um property administrators, um which is a little bit particular for Danish uh law, it's for co-op communities and partly owner communities. Um uh yeah um we are uh a real uh jazz enthusiast, so using Django uh Reinheits framework just makes uh so much sense.

0:43

Speaker 2: Yep, absolutely. So um just a very short uh shortly why we are here. Uh we went to GiancuCon 2022 in uh Portugal Porto. Uh and we saw a lot of cool stuff that inspired some of the decisions we made technically at that point in time as well. We wanted to Just tell our story about how we used the Django admin to build most of our uh application. Uh it's not a recipe for any application, but we had a lot of uh great joy of uh basically building on top of that. Um so we just wanna give a bit back on how we uh got some cool stuff

1:28

Speaker 2: basically. Um This is uh this is what you meet when you browse around the internet. Um it's it's mostly saying that don't use Django admin for anything, uh like don't build on top of it. Um this is all basically uh have written after we started our project. Uh I think maybe luckily because otherwise we might have been discouraged to use it as well. And we might not have been where we are today in terms of having a successful product uh built on top of it. Yeah. Like even the ad uh the documentation of it says don't. But um we got a lot o out of it.

2:15

Speaker 1: Yeah actually I'll just mention I think the most important word here is intended uh because it does leave the door open, right? Um yeah so um I just want to go through our timeline uh quickly because it's sort of part of the important history. Uh our colleagues started this sort of property homepage application in 2012, so quite a long time ago. And they built it. They had, I think at the time where we entered uh twelve um customers, it's uh

2:43

Speaker 3: business to business. Uh and there were twenty modules doing quite a lot of um critical um infrastructure for our customers Um and a lot of it was uh you know how uh back at that time there was a lot of printing, there was a lot of uh sending uh stuff around. Uh part of this Danish law is that the board has to sign if the when when there's a new invoice everyone has to sign it and then it's sent back. So There's a lot of just paperwork and sort of documentation and they they digitized this. Um and so uh we we entered in twenty seventeen. It was at the time they did uh a responsive website to begin with and just um a lot of things had to be changed. One thing also was that the main login was each the property had like one login per board, which would mean uh you know

3:28

Speaker 3: when the board left, uh one member would be leaving, they would still have the access and it would be like one, two, three as the password. And I think You can hear sort of the GDPR monster screaming uh ha. So without we had to do, you know uh use a sort of personalized login. Um and uh we knew we didn't have a lot of time. There was about nine to ten months to just sort of duplicate um these modules, but also there were thoughts of doing like a whole messaging uh notification system. Uh so there's definitely uh a pretty uh tight uh schedule. Um so I started working on it pretty quickly through uh first um sort of iteration out because I could see it wouldn't work with the messaging system Um and uh Johan

4:14

Speaker 3: uh joined uh doing frontend uh in June. Uh the first customer was mighty created these nine, ten months later. And Pretty much exactly three years uh later we sold to EG which is a major s Scandinavian software company. At the time we had a hundred and fifty thousand users, all uh Django Elmin staff users Um we were two and a half developers and now we yeah you can see the the figures. And we just hired a new um developer mostly so we could be here today. He could be um taking care of business. Um but the so you see the sort of point is uh one developer doing a lot of stuff and uh we've the whole you know journey has just been pretty much your hand on me Doing the whole thing and um yeah, that will uh send me on. So this is the

4:59

Speaker 3: yeah it's a little bit probably not detailed But this is actually our Django L menu. And I think you'll recognise some things like searching, filtering at the top right. The menu is a little bit more like uh intricate. We have uh actually three, there's a profile menu, there's a community member menu and like the more general but uh nested menu. And then you may perhaps you can see the toggle list uh that contains uh more information and the the dot menu. So we added a lot of stuff to it And yeah, this is just uh part of it. So um when I started building it, I thought, well, I have fifteen to twenty uh modules I have to redo in nine months. And five of those were like really customized stuff and the rest was like very straight up crud

5:44

Speaker 3: with tiny changes in label labels and stuff. And I just thought if I have to make this by myself, I have to go really fast. I I was thinking, you know, should I go expand, rest um like pretty much everyone else and I just knew I I wouldn't be able to make it So I thought I'll make these 15 straight up product patients during Django Elmin. I know I can do it fairly easily. The old uh application didn't have like even basic searching and filtering and stuff so I knew I could add lots of value even from the get-go uh on top of the duplication of

6:20

Speaker 1: of it Um and also I knew I mean just building a messy messaging app and notification system, I could probably spend the whole time just doing that myself. And I had to do that also in these 10 months. Um and I thought, well the main thing is actually I might just go here and show you um if if you can tell this is Part of the permission diagram we have the tutu which are is this our admin users.

6:48

Speaker 3: We just changed the name into tutu We have um partners which is our customers. We work closely with them so we call them partners. We have provinces which each partner has many, like a portfolio of partners. uh properties sorry and the support and resident um permissions lots of permission on uh permission handling and i knew that that was something I could probably um get um uh auth uh groups to do. Only thing is if you're a board member in one community, maybe you're not in the other one. And everyone could have uh multiple communities Um so I had to tweak it. But it turns out it was actually fairly easy. Um I spent probably like one day doing it, just sort of a

7:34

Speaker 3: uh proof of concept and I thought wow if I can do this uh that easily That really helps me in uh uh solving all the permission issues, and um I can get going with all these um really easy crowd applications. I thought, okay, go. And I could start building first the straight-up stuff and then you know see how much how much time I'd have to do the customized stuff uh afterwards. And so we have a bunch of admin sites. As I mentioned before, they take care of some permission handling but also like what widges to display on the dashboard. other things not that important. The main one being contrived auth groups because everyone can

8:19

Speaker 3: have sort of like a mishmash of the groups overlapping and they all take care of the the module admin um permissions. Um yeah and then the thing is um so if if you are a direct customer of ours you have the portfolio of communities that you can access And um I'll show you the code later, uh which is super simple. But then also if you're logged in just to one community, you want to just show the ch the scope of the data just within this community. And you can see it in the in the domain it's by a subdomain. Um uh yeah. And then we have we have a little bit of also some um properties communities have some sp uh apps uh some others they don't, depending on what their

9:06

Speaker 3: um property administrator. You know, maybe they have to pay extra for it or whatever it might be. Um and so that is handled specifically in each uh model element And we had a little bit of row level permissions, but not very much. Um so we didn't really need to uh implement some other um um library for it or anything And it it actually turns out that this is the only place where we really have straight up copy pasted um Django uh admin. uh source code uh which is a little bit painful because everywhere else it seems like there's always some option of just like uh hooking yourself in but this one place I really wish uh allowed for better um sort of um just extending Um yeah. Um

9:51

Speaker 3: I hope you can see this. It's just it very like uh basic stuff. Ours is uh it's a lot longer, but I just wanted to highlight some things. You saw the the list display toggle fields Um which so they open the expanded list. We have menu icons, just a few things, you know, super easy stuff like uh the save button label. Sometimes it just had to say something different than save. Um so we can override that. Maybe we had to also fix the template. But it yeah, it's uh you know very straightforward, like uh changing the the title uh above stuff like that. We have lots of that. Um then I just want to just the point type the pinpoint the the query set because every

10:37

Speaker 3: almost every model uh inherits from the community based model so they have the community uh relation. And that makes it super easy because as soon as there's a subdomain we can catch it in the middleware, we can uh filter and get queries that means uh we make sure that you know there's just uh the the subset that should be there. Really easy. Uh and also there's a little bit of like so so maybe at one um partner employee will only have a subset of the subset and we can handle it and that will take care of all the the model elements that um inherit from it. So that it it just shows you a few lines that uh take care of so much business for us. Um when I guess about a year ago we we decided to do uh uh

11:25

Speaker 3: an upgrade of our front end and We didn't actually really have time to do any uh sort of more um advanced uh activity, but uh I thought we'll give it a shot anyway, uh because I really wanted to have that more of um Like active feel like I hadn't forgotten about doing the the spa feel and I think mostly we really missed it for the change lists. So I'll just go ahead and show you what we uh what it looks like. Uh see so there's infinity infinite scrolling, there's uh and it's actually pretty fast, there's about uh 800,000 rows I think. Um there's active searching Uh and you'll see also extra filtering in a second. And the thing is, as I was just sort of poking around to see, I knew I didn't have the time to build this from scratch myself and I was thinking

12:16

Speaker 3: that must be lots of stuff I can reuse. And it it turns out um there's a so we did an active change list uh view that we can actually turn on just sort of by a feature flag in the top of the admin model And this is pretty much it. And the thing is I was looking at it yesterday and I realized none of these lines of code was actually something I created. It was it's all taken from someplace in Django admin. Uh and when you look at it it it it's it's it's very simple. I think uh you will see also in you know getting the changelist instance. Building the form set and then the start of the show, the really the big attraction is the changelist with Chris. It's because it actually does all these things and it n now it turns out it it does the same thing in many pla

13:02

Speaker 3: many places. And first of all it calls what you just saw before on each model admin. It calls the get query set directly on the model admin. Afterwards it it handles this. So if we have permissions in that it will take care of that. It'll go on, it'll do uh filtering, searching, and ordering, depending on of course the the custom parameters Um so much stuff goes on, it's you know for free. Uh it was already there. Those pagination handles, there's a little bit of extra details in there that I left out to make it uh fit in into one screen And uh instead of going to a template, uh doing some um template text, going into another um function and stuff, uh we're just doing uh calling the the just result

13:47

Speaker 3: list function directly and uh putting out it out in our own uh template. And then you can see we can you can the the chancelist uh um HTMX um element and below is the switch element s and the and then there's also the The i infinite the scrolling element and they all just call the same function doing the same thing. There's so much reuse in this and it I think it took me to get the the basics of it, you know, a few hours going and I was like, wow, how long would it have taken me if I had to do all these elements sort of over again uh from uh building from scratch Um yeah, then uh right after I was actually looking into getting some kind of internal tool for for searching uh easier because we have so many

14:39

Speaker 3: Different uh modules, lots and lots of uh data and often for support um uh issues for instance someone has to find a specific invoice for a specific community And and there's a little bit of like a clicking and lots of sort of performance going on because we have to load everything uh in the beginning. And I was thinking, hmm, what uh what can we do? And I saw someone doing like uh a modal that you could uh access from anywhere uh and sort of just uh input a little bit of data and and then have active searching right there. And so I think uh yeah here it actually is So this this is a a test partner um calling uh community, a property, and this is the name.

15:25

Speaker 3: And so it it just comes straight up, we can tap to it, we can go to it directly instead of you know going to the menu, calling the changes, searching for it, clicking Uh and then we're there. And we the thing is, uh let me just actually pause that. Ah, sorry. Uh the thing is that um ah I'm going many places. I can just tell you uh uh uh Hold on just one second. Here we are. Yeah. Uh you see the admins? So all it really takes is adding the admins that we want to be able to search. And they pop up in the auto field, autocomplete field, and because we have this uh which you saw before the active change list, when we can actually get the m the model admin class

16:14

Speaker 3: and we can um uh instantiate it, we can call it directly. Only thing is, I don't know if you noticed, but Usually we have like lots of list display fields that could be six or eight. And I just wanted you know a simpler version to fit in the model. So I had to do a little bit of monkey patching to just get like the basic uh list display uh fields. And then returning the active changes. So what came from before, from the individual uh model and it could just be reused in this instance. It's like so much uh value and it turned out that in the beginning we used it just internally, but of of course our customers really enjoyed this also. It's just a little bit of tweaking So I hope this uh leaves you with a little bit of an impression of wow, this

16:59

Speaker 3: all this stuff that can be reused and it's actually right there. Um And uh s yeah, let's just uh see show of hands of who is using the Django admin like almost every day How many has been looking into contribe uh admin options pie within the last week Yeah, see and it's it's that's interesting to me because that's like my um that's my home. I live there. Uh uh there's so much good stuff, there's there's so much that can be reused And I was going to say that this is all very easy, but I I heard the I think it was Mia talking about she was sort of looking for some of the same solutions and she found it hard. And we've been doing it for so long that it's a little bit hard to say what it was actually like in the beginning. But

17:45

Speaker 3: I would say the time that you spent sort of getting to these places uh within the core uh admin uh source code is really uh it it it ri it returns like tenfold.

18:01

Speaker 2: Alright, so obviously uh we had to do a bit of front end tweaking as well, because we could. Um We did a lot of back-end stuff, obviously. You saw a lot of the new design as well. This is uh this is what you get out of the box um mostly. This is actually a fairly modern version of of the admin. Um Um but we had to do more. So let's go a little fancy. This is where we started. This is the first version. wanted to do uh use most of the uh default sections. We kept the m most of the sidebars, uh the dashboard is obviously something we stick together as well.

18:47

Speaker 2: But um Otherwise the menus and and a lot of stuff in terms of rendering the lists and uh inlines and all this stuff is fairly um unmodified I'd say. Um We uh we reused that l a lot in that way, um and got very far with that actually, uh without redoing a lot. So mostly we kept most of the HTML structure which allowed us to reuse a lot of default admin functionality in terms of uh default scripts. Also admin um extensions just kept working without uh too much uh In modification basically. But we kn did a lot of restyling, obviously. Which is uh most of the work actually.

19:32

Speaker 2: Um But uh we made a version two as well. And uh for that part we kind of wanted to scale down whatever didn't work. So we tried to keep what uh worked, keep what um sparked joy. Uh we wanted to reduce a bit of tool chain, we th wanted to modernize a bit But still leaning into Django, Django admin, relying on server templating, all this stuff that you kinda lean on Django to do a lot of uh the hard work uh that we already are doing. So this is what it looks like today. Um uh We did some uh besides the visual stuff, uh we did some other stuff to do some accessibility tweaks.

20:18

Speaker 2: Uh we wanted to make it a bit easier to do s some of this kind of stuff um uh in a more modern way. Uh so we did redid a lot of actual templates, but still keeping the structure of the templates in the base templates of the admin, but otherwise tweaking the HTM To make sure that we we got some of the new features we wanted out of it. We used a lot of uh web components um gonna show a bit of that as well. Um but otherwise we try to scale down use modern uh uh uh uh front end tools like uh Um excript the uh module uh loading of the JavaScript. We used a lot of HTMX as you've seen. This is very cool to make it uh feel a lot more uh a bit more interactive. We used slippers, which I

21:05

Speaker 2: uh love very much. We saw the storybook Django uh from Gibo, which is somewhere here probably um Um we saw some interaction with that, doing some web components and doing some componentized uh Django uh to make sure that it's more organized when you build this stuff out. Um But otherwise of all the money stuff is just forms fields uh a bit of uh layout supported by crispy forms uh and some some good stuff in that way. Um This is just to I saw some Alpine jazz and some HTMX. This is uh just uh um web components.

21:51

Speaker 2: Like native browser stuff. We use some slippers in here, we use some I'll show you as well, but otherwise it's fairly just native web components. I just want to go buy it because I saw the other stuff. This is Just works in the browser, it doesn't do anything else, it doesn't um needs to be compiled. There's some uh if you want, you can do some local styling as well, which keeps it simple at start. You can extend that out if you want. But otherwise, um I know this might look a bit intimidating uh if you don't uh not used to it, but it's it's very simple stuff. This is the The Clarish Shadow DOM version you got a template inside and the style as well. But you can also just use the um the normal snack bar that we have here and without the all the inner fittings

22:39

Speaker 2: and you can with a bit of scripting you can hook into that and use uh the nature browser also uh binding um so when you the classic problem of uh changing the DOM uh or injecting it with HTMX for example, um you have to rebind events if you've got a click uh like eventlessness of any sort. This stuff uh makes it all just kind of very easy to just use the browser's native functionality of it and uh it kind of just works. Um the It can be a bit verbose, but otherwise the idea of it is is fairly simple. You can connect you can add event listeners as soon as it's injected into the DOM with a connected callback. Uh you can um observe some attributes if you want to react to anything what

23:26

Speaker 2: being modified outside from the any from any place, scripting or otherwise. Uh and you just kinda define uh uh to be uh to be basically observed. So whenever it's injected into DOM somewhat it's uh automatically uh loaded. And so this is how we use most of this. We Make a slippers template of it and kinda use it this way in our in our templates. Uh fairly uh fairly simple stuff Um some other admin enhancements.

23:58

Speaker 1: I think we'll probably uh do them really quickly. Yes. Um

24:01

Speaker 3: let's just see. We have um yeah, active uh changeless fuels. With the ACMX, also super simple, really it's a generic solution. We can use it pretty much everywhere I sec i except for like file uh all uploads. Uh another example actually Yeah, yeah, I should just mention I think that one of the really uh m completely shitty UX solutions in the admin is inlines and we've ha had so many customers um uh wanting to delete something and they uh hit the checkbox and then they hit delete on the whole object and so everything is deleted. Um and yeah so but one thing we really wanted to do also was do inlines but differently uh with

24:47

Speaker 3: HTMX. Uh and so this is um a tap of and it's again it's a to me super simple uh solution, just reusing admin

24:55

Speaker 1: stuff. You can see you can And it's yeah, it's uh just an inline and it we it's fairly easy to reuse with the mixins and stuff. Um yeah, so there was a lot of things. Um And back to you know, what was intended. Well sometimes things can be

25:16

Speaker 3: used in a different way than they were intended.

25:18

Speaker 1: Uh personally I'd like to visit someone that had uh bubble wrap as uh wallpaper and you can go poke it.

25:24

Speaker 3: Um uh I I hope That you um get an impression of uh this sort of um taking things apart and uh reusing them uh and sorting maybe looking a a bit deeper. I I think one of the things with the admin is that it there's a there's a lot of documentation but when as soon as you have to customize you have to actually look at the source code And so you you do need to just go and but then it's fairly easy to understand um and there's so much to to also learn from it. Um yeah.

25:57

Speaker 2: Uh yeah. Uh basically what we want to say here is uh you can go very fast with uh the admin tools. There there's a lot There's a lot to uh get into. There's a lot of code to read if you want to use it, because you wanna get uh fairly intimate with it. Uh but otherwise there's a lot of good stuff.

26:17

Speaker 3: And just to um

26:18

Speaker 1: to end, I think from a business perspective, what we uh ended up being able to do with the admin uh simply wouldn't have happened. Um at that time I had only done a little bit of um Django Rest and uh and so forth. But I think Still uh I I think Carlton also mentioned it yesterday, you know you kind of need um two teams and uh if if nothing else you need to sort of break your uh brain into two teams. And uh for me, you know, you we got everything, we got the change list, we got uh add and update uh possibilities. kind of for free. Um and it really sort of um made it uh all happen uh in the short time that it had.

Questions this talk answers

Can Django admin scale to a large SaaS application with hundreds of thousands of users?

Yes. ProBo built most of its application on Django admin and had about 150,000 staff users when it was sold, approaching 250,000 users later, with the core product largely built by about two and a half developers.

Discussed at 0:00

How can Django admin permissions support users who belong to multiple communities?

ProBo used Django auth groups for module permissions, then customized the setup so a person could have different roles in different communities and belong to multiple communities. Admin sites also helped control permissions and dashboard widgets.

Discussed at 6:48

How do you restrict Django admin data to the current tenant or community?

They captured the community from the subdomain in middleware and filtered the queryset through a shared community-based model. The same mechanism also handled narrower subsets of data for individual employees.

Discussed at 10:37

How can I add infinite scrolling, live search, filtering, and ordering to Django admin change lists?

ProBo reused Django admin’s existing changelist machinery: it already applies the model queryset, permissions, filtering, searching, ordering, and pagination. They rendered those results through HTMX in a custom template and enabled the active change list with a feature flag.

Discussed at 12:16

How can I add a global search modal to Django admin?

They registered the admin models they wanted searchable, displayed them in an autocomplete field, and reused each model admin’s changelist to return the results. A small amount of monkey patching reduced the displayed fields so the results fit in the modal.

Discussed at 15:25

How do you customize the Django admin frontend without losing its built-in functionality?

ProBo retained much of the admin’s HTML and template structure, which let its scripts and extensions keep working, while restyling the interface and selectively replacing templates. They later added HTMX, web components, module-loaded JavaScript, and accessibility improvements while still relying on server-rendered Django forms and templates.

Discussed at 18:47

How can HTMX improve Django admin inlines?

ProBo replaced the standard inline workflow with an HTMX-based version, reusing Django admin’s inline and mixin machinery. This gave users a safer, more interactive way to add and delete inline records.

Discussed at 24:01

Note: We understand that names change, people change, and bodies change. We respect each individual's journey and privacy. If you have any concerns about a video or need us to remove content, please don't hesitate to contact us. We will handle your request with care and promptly address any issues.

More videos from DjangoCon Europe