Transcript: Optimizing Django Queries - Jamie Matthews
Hi, this is Will. A quick note before today's episode. I'm offering a Black Friday sale,
50% off my three books, Django for Beginners, APIs, and Professionals. Good until end of day
Friday, November 26th. Link in the notes. So if you're thinking about learning Django on your
own or for someone else, now's a good time. On to the show. Hi, welcome to another episode of
Django Chat, a fortnightly podcast on the Django web framework. I'm Carlton Gibson,
joins us by will vincent hello will hi carlton hello will and uh this week we've got jamie
matthews with us who's um dab apps creator of various uh packages in the django um ecosystem
long time django user and whatnot so we're going to chat about all those things hey jamie thanks
for coming on hello folks thanks for having me on oh thank you for joining us quite excited you've
been um producing some really interesting things that i'm keen to dig into but before we do thank
you before we do all of that um let's do our traditional um what's your backstory and how
do you get in and tell us about your your how do you find django okay so i i'll introduce myself
first so i'm a technical director of dab apps i suppose in america that might be cto um we're a
kind of web and mobile agency so we build bespoke web apps mobile apps uh usually with api backends
of some sort um we use django for all of our server-side code we're based in brighton which
is on the south coast of england then we've got an office in wales as well about 30 people
17 18 devs a mixture of back end and front end full stack um and we've probably built over the
years i was trying to add it up it's definitely over 50 and it might be kind of closer to 100
django projects um anything from like small code bases you know a few thousand lines of code up to
our biggest projects are sort of 70 80 100 000 lines of python um so we have some some really
big projects or well relatively speaking i think yeah i mean um you said 30 people right did you
say yeah so yeah 30 people total yeah so that's quite a big agency i mean you've got you know
there's a lot of turnover of work there yeah indeed yeah yeah i suppose we're we'd be considered
fairly big do clients come to you asking for django or because of django or do they come to
you and then you say, this is our toolkit we like to use? It's a mixture. Most of our clients
don't care or don't know or care about the stack other than the fact that they're happy that we're
good at making decisions about what technology to use. We do sometimes have clients who come
to us specifically for Django. That tends to be clients who have existing code bases that maybe
they've had someone else build and and they need that sort of taking over from people who who know
how it works okay so before we dig in further i was gonna ask you say you did mobile and native
apps and um these kind of things as well as web apps so can i just ask about the front end
integration like how do how do you um map between django on the back end and what's going on on the
front and next that's quite interesting so most most of our well all of our front ends are react
mostly written in typescript and for mobile apps we use react native um so yeah essentially we
build um apis with django rest framework um and we have uh you know yeah react and react native
apps that talk to them so yeah so django rest framework we have to we have to mention it here
because um the thing you didn't mention about dabs is that's where tom came from was tom christie c
yeah so i i realized i didn't i didn't really answer your question which was how i how i came
to Django. So I'll loop back around to that one. So I think I found, I was trying to remember where
I first used Python. I definitely came out, I did a computer science degree in Manchester and I
definitely came out of that with an awareness of Python. I can't remember whether I used it as part
of the course or whether I just sort of found it in my, you know, in my free time. I then moved
down to brighton to do a master's and i use python quite a lot there doing kind of scientific
computing type of stuff when i finished my master's i went and got a job as a web developer
but doing php um but i used to get so brighton has this really amazing sort of tech scene with
lots of meetups and there was one which i used to go to a lot which believe it or not was called
flash brighton right do you remember flash well yeah yeah a few years ago wasted half my teenage
reduce with that well indeed so i didn't really do very much flash but i kind of went there because
when they didn't have flash topics to talk about they got all sorts of other people and all sorts
of other technologies and one of the speakers there was simon willison who of course was one
of the original co-creators of django who at the time lived in brighton um so he was giving a talk
about django this would have been i think i think it was early 2009 so it would have been just after
1.0 came out and kind of just before 1.1 came out um so i went and saw this talk obviously i was
doing a lot of web dev at the time i really like python and this was like wow now i can build
websites in python this is the best thing i've ever seen so i went away and kind of dabbled with
it funnily enough the very first bit of django that i used was inspect db which i imagine basically
nobody uses um because what i did was we had this kind of internal tool it was some sort of
inventory management system which was like a php app that talked to a mysql database
and i kind of went oh watch this you know i went and pointed inspect db at the database
generated all the models wired them up to the admin and within about five minutes i just had
this like working admin system for this for this app and of course everyone was very impressed and
they all went wow well done let's go back to writing php um so um so yeah i did that for a
while played with django in my spare time you know got a book about it learned as much as i could
and then eventually myself and a couple of colleagues from from my first job decided that
we were kind of going to go off and do our own thing set up dab apps from day one it was it was
all about django um our first project was uh it was for a company who were a supplier of tesco
which i'm sure everyone's heard of um and so our very first project was kind of quite high profile
very briefly featured on like the front page of the bbc news and it didn't fall over let's just
have a footnote for american listeners tesco's is a large supermarket chain yeah that's it walmart
i've i've been to your side of the pond so i know i know it is but if i hadn't i wouldn't yeah so
other supermarkets are available of course um yeah so it was briefly quite high profile um and
you know it it worked really well it was really successful project so we kind of we got that we
made a few more projects and then at some point i'm trying to remember when it must have been
probably 2011 maybe um i met tom at a python meetup in a pub and at the time i remember him saying
so i'm i'm working on this this thing it's kind of it's like a framework for building
rest apis in django it's like a django rest framework but i'm really struggling to think
of what to call it so um so i said well you know what about django rest framework and he said oh
that's a good idea i bet i bet that would do well with like seo you know that that'd be nice and
easily googleable um so you know uh step forward a few months eventually we end up hiring tom he
was our first employee after the three founders um and not a bad pickup yeah yeah um yeah no that
it was really good he was really kind of crucial in in shaping a lot of the early tech decisions
at dab apps for sure um and he kind of um he was working on client projects for us but at the same
time he was also working on rest framework and he if you remember one um quite a while ago he did a
kickstarter to fund some rest framework development and he did that work while he was working for us
and so we used to kind of sit opposite each other and bounce ideas around and
i think i'm kind of i don't i haven't contributed a huge amount to rest framework but
i think i'm responsible for like serializer method field the original version of that was me and like
um you know things like that um so so so that was fun um so that was kind of back in the day
and then yeah we we sort of transitioned over to because originally we did i guess you might call
it a classic django app where you do the templates on the back end you know it renders html on the
back end that was you know for the first few years that's what we did and then we moved over to this
sort of api driven um react app type approach obviously using using rest framework um and that's
that's what we've been doing ever since really although i have kind of recently got quite
interested in the whole unpoly htmx thing which i know you're all fans of well i've been using it
on projects and it's just amazing to be honest for me it really is just like oh and to go back to
writing templates and just oh i need to you know so i've got a i don't know a form view and i just
want to you know jazz it up a little bit and a couple of things and it just works and you're
like oh yeah this is yeah this is good this is good it is so i was going to ask you what do you
think so i i really like it so we've recently been i've i kind of i guess i htmx i really like
the philosophy so I think the guy who you know he's the main developer on htmx is is amazing and
I think he has some brilliant ideas and I think he's basically right about everything um but what
we've actually been doing from kind of a practical point of view we've been using something called
unpoly which is um I hesitate to call it a competitor because I think they're very much
in the same vein and they're very much they support each other um but unpoly is I would say
a bit more full featured from the point of view of actually building web apps so it's come out of
an agency uh in in germany i believe who do rails backends um but other than that they're very
similar to us um so it allows you to do stuff like it very easily lets you um navigate around
without doing full page loads kind of makes makes it into a bit of a single page app and that kind
of stuff so that's been interesting and it's nice and easy to integrate with with react where you
need to drop some react components in well this was kind of what one guy so if you're you're
essentially a react shop and you're you're fully invested in there and then a new technology comes
along how do you kind of smuggle that in or how do you have to do a sort of separate project to
experiment or do you know how do you get going with the new technology how do you give it a go
because that's that's always a question i'd like to use htmx but how can i you know the work you
already use some others so it is quite a high risk thing to do i would say change the tech stack
particularly in an agency where everything that you build kind of exists in parallel if you like
you know if you're a startup and you switch technology once you've deleted all your rails
code and rewritten it all in django then you can like forget rails ever existed and you never have
to think about it again whereas in an agency if you switch from rails to django you've still got
a whole load of rails projects that sit around that you're never going to be able to rebuild so
it is a high risk thing to do it's very important that projects have a similar structure so that
you can switch exactly exactly and you know people you know are context switching a lot and so um
yeah it's very very important that things look as similar as possible so like i say it's a high
risk thing to do i think that the key is to try it on a small scale first so try it on internal
projects which we did and we got really confident and comfortable with it being um something that
we could we could experiment with a bit further and then you start introducing it into sort of
smaller scale client projects and um it's been it's been really good so i'm like you know we're
not we're definitely not ditching react because we do build a lot of projects which are very much
what react is good for you know that very dynamic user interface type of um type of thing but yeah
we're experimenting i imagine that's when you switched over to react that was similar calculation
around you know is this something we can commit to is how sustainable react be right this is like
you've been using React for a while. I mean, React has changed quite a lot over the years.
That's true. I think React was maybe a bit of an easier decision because we knew that we had
to build the sort of things that React let you build. But before React came along, we were
building them in all sorts of slightly janky ways, you know, starting off with jQuery, and then
maybe we did a bit of Backbone, and we tried out a few different things, and none of them really
felt very solid. And then React came along, and it was like, oh, yeah, yeah, that makes sense.
someone solve that problem now carlton you're still doing objective c right no no no i'm just
kidding no i mean i i'd say that with a sort of tear in my eye because i do miss it um but this
sort of last 12 18 months it's all gone swift now it's like objective c doesn't quite you know
you can still do it but actually going back to it it's you don't remember it's not as nice as
you remember it being if that makes sense like you have these fond memories of objective c but then
And it's not as good as Swift.
It just isn't.
So I've kind of, you know, chopped up.
Anyway, that's it.
It worked at Django.
So project structure, you kind of mentioned that.
I'm curious.
So presumably you have within the agency a default that you like to use.
I'm curious what that looks like around, especially how you organize your apps.
Because we had Ned Batchelder on recently, and we were talking about, you know,
is there a code base that's mature
that people can look at as a best practice?
And he was rightly saying every large thing
is kind of has things baked in that if you could change you would um but since you're in an agency
you you have maybe more of a chance to have some uh greenfield projects where you can structure
things so i'm just curious how you like to do it because everyone kind of does it a little
differently at scale i find yeah i mean we try as much as possible to not deviate from
uh django's sort of best practices i guess so um we it looks a little different to what you
would get if you just ran start project um but but essentially our our project template for the
past probably 10 years has been essentially what django gives you with some react stuff in there
as well all of the apps go into a separate top level package so instead of having just a big
kind of list of apps in your root directory they go into a separate top level package
that package is always has the same name so it's always called project
rather than being called the name of the project, right?
So the apps are called project?
Well, no, just sort of the top-level package that all the apps are in, if you like.
So, yeah, I mean, it's not a million miles away.
Having said that, again, sort of recently over the past year or so,
we've started to experiment a little with slightly different structures.
I'm increasingly of the opinion that dividing things up into apps
is not always a good idea um a couple of reasons for that one is it's when you start a project
you often it's very difficult to figure out where to draw those lines between things
and if you're not sort of building for reusability in terms of those apps which usually are not when
you're writing bespoke code for someone else um drawing those lines in exactly the right places
is quite hard and it's then quite difficult to change it um if you get it wrong so if you
you know django's migration framework doesn't really handle well actually i just want to move
this model between apps very well or certainly it didn't the last time i tried to to do it
so okay then but you so the opposite of that is you've got a giant models.py file or
essentially so you have a models.py package which has in it a file for each model okay and then you
import them all at the root so you essentially you have you have a models app if you like which
has got all of your models in it and then separate to that you have an app which has all of your
views in it right because really you know views and models are almost at right angles to each of
the kind of cross-cutting uh domains right because often you want different views to all talk to the
same set of models and so packaging them up together um in in an app always feels a little
bit odd to me particularly in bigger projects yeah and you you're always got the view that
imports the model from the other app and exactly yeah okay interesting so i wanted to ask you about
your open source work then jamie because um there's a couple of big projects that i you know
just um so i'll ask you about a couple and then you can um riff on those and then if there's others
you want to tell us about and that would be awesome but the two that come to mind are zen
queries and then the newer one which is django readers so do you want to tell us the backstory
on those and you know what the motivation is and we can chat chat about those packages because
they're amazing folks you should check them out sure okay so zen queries let me first explain
what it is at its core it's a context manager which lets you say which lets you mark a block
of code as not being able to run queries not being allowed to run queries so if you try and
run a query i.e you know evaluate a query set inside that block it will raise an exception
you're just not allowed to do it now why would you want to do that um what we find particularly in
in big django projects and i guess this is kind of the classic object relational impedance mismatch
thing right so django encourages you to put your business logic in uh in in the model layer
essentially so you have model methods or you have query set methods which you put your code in and
then you call that code from a either a template usually if you're if you're doing your html on
the server thing or you call it from a serializer and often you know the templates can do things in
loops or they can do things in doubly or triply nested loops or serializers can be very deeply
nested if you're pulling back quite complex object graphs and what ends up happening is that you
end up with the classic n queries problem right so you accidentally without realizing it perhaps
access an attribute or call a function call a method on on a model which ends up incurring
one or more database queries and if you do that in a loop or particularly in a nested loop
you end up with tens or hundreds or i've seen thousands and thousands of queries from from
single views but there's there's not really any sort of visibility of that if you like you know
you can't see that happening um and that's because the uh the code that calls the methods or the
calls the code that accesses the attributes is sort of over here in your templates or in your
serializers but then the code that you have to write in order to make that efficient is over
here in your views usually right because you would usually define a query set attached to a view
and so what you end up with is this kind of weird like binding between the two things
and they're very dependent on each other but the dependencies aren't visible in the code
and so what I kind of you know thinking about this for a very long time you know lots of years and I
spent a lot of time tuning query sets and prefetching and select related you know django
gives you the tools to solve these problems right but it's always for me you create the project the
problems and then you have to solve them you shoot yourself in the foot and then you wait for it to
hit you know you splint it kind of thing why is this feeling slow exactly so so what i wanted was
a way of saying well actually how can we avoid this how can we make this not be a thing so the
The point of Zen queries is to allow you to say,
okay, as part of rendering this template
or as part of accessing this serializer.data,
when you're kind of serializing some stuff with a serializer,
you're not allowed to run any queries, right?
If a query happens as part of doing that thing,
it blows up, it will give you an exception.
And so what that forces you then to do
is to think about it when you're writing the code.
So you have to, before you access that attribute in your template,
you have to have select related or prefetch the query set.
And as soon as you do that, then it's fine and it all works.
So the idea is, so it gives you this context manager,
but then it also gives you a few little tools sort of built on top of the context manager.
So it gives you a replacement for django.shortcuts.render,
which will allow you to render a template wrapped in the context manager.
So you just switch your import at the top of your views file,
and it kind of, you know, all your templates blow up
when you're running queries in them.
Or it also can give you a serializer mix-in
and a REST framework API view mix-in,
which will kind of magically mean that when you try and access
your .data attribute on your serializer,
again, if that runs any queries, then it blows up.
Yeah, and that's a good way of enforcing a certain amount of discipline.
Exactly, yeah.
And it sounds arduous, but really it's not.
All it's doing is pushing a little bit of work
to the start of the project
rather than six months in when the client's upset
because their project's running really slow, right?
And so just as a matter of best practice,
you use this on every project from the beginning?
Exactly. Yeah, that's the idea.
And it gives you an escape hatch as well.
Like if you need to do something,
well, actually, you know, I know what I'm doing
and I really, really do just need to run a query here.
It also comes with another context manager called Queries Dangerously Enabled,
which turns the queries back on again just for that block.
That's nicely named, nicely named.
Exactly, yeah.
And similarly, there's a template tag, which does the same thing.
Okay, cool.
So any more questions on Zen Queries?
Have I explained it?
Does it make sense?
No, no, that's all fine.
I think I would just say give it a try because I've used it myself.
So the other one then is that I'm really excited about at the moment.
and i i'm still on the um the fence i haven't you know i've played with that i'm a bit like do i dare
use do i dare smuggle this into a real project it's um django readers so yeah you tell us about
what's going on on that one because that's quite yeah i'll try so this this is one of those things
which is is quite difficult to explain purely over audio it makes a lot more sense if you can
see the code um so this is if you like the next step on from from django zen query so if zen query
says well you can't run a query here but it doesn't really give you any help of how to structure
your code how to how to um you know correctly prepare in order to render things by um pre-fetching
and select relating and doing all the other things that you need to do in order to make that query
efficient so the origin of django readers was in another project which also came out of dab apps
written by Paul who's one of our engineers and that was called serialization spec mixing
and as you can imagine that was very tightly bound to Django REST framework so the idea of that
was that you would have a what's called a spec which is I guess kind of the closest thing that
you can think of is it's a bit like a GraphQL query but rather than being in your front-end
code it's in your backend code if you like so it's it's a property of a rest framework view
spec equals and then it's a list and in the list you can have strings and the strings are just
field names on on the model yeah and you can also have dictionaries and the dictionaries the key in
the dictionary is the is the name of a relationship so let's say you have you know a book with an
author or whatever your your key would be author and then the value of in the dictionary is another
a list which specifies which fields of the author you're interested in so you kind of nested
serialization format exactly so so it's a very simple um spec for saying here's all the fields
that i'm interested in and then what it does it generates both a query set which is sort of
surgically pulls out exactly the data that you want from the database and not only does it
automatically prefetch and select related and and all of those things it also uses dot only so that
it only pulls back exactly the fields that you've asked for uh so you know normally a django query
set does the equivalent of select star essentially it doesn't it explicitly lists out all the fields
but usually that's fine but if you know let's say you've got some huge text field in there then all
of a sudden that can be slow or it can use lots of memory so or you're fetching your your custom
user model which has got 300 fields on because you've used it oh here we go exactly this is the
running gag it feels like you have some experience there yeah but anyway but the point is it just
gets the first name last name it doesn't exactly yes so so uh it pulls out only the data that you
actually need to uh you know create your api endpoint shape and then the other thing that it
does is it generates your serializer for you so it creates a serializer class with some nested
serializers which precisely serializes exactly the thing that you need so you just write one
quite concise thing and you get efficient queries and serializers kind of free so paul wrote this
thing amazing like beautiful bit of api design i don't think he would be upset with me for saying
that the code was kind of gnarly um so it was very much one of those projects where it's like
let's get it to work of course he understood it all but um it wasn't the easiest code to follow
it wasn't the easiest thing to maintain and when we sort of tried to add features and fix bugs in
it it was like well actually there aren't many people who really understand this well enough to
do it so that's sort of that's one side of it so if you just park that in your brain that's the
that's the high level thing we'll come back to that in a minute okay so that then got me thinking
okay so what would this look like if what we if we built it in such a way that it was simple
okay so rather than being this really complex gnarly thing rather than being bound to rest
framework very tightly and only working with rest framework what if we could turn this into a bit
more of a generic concept so this goes back to that thing that i was talking about earlier around
around model methods and model attributes being very tightly bound to query set calls so
the two places where you generally put bespoke business logic in a django project
for you know for reads if you like for for returning data from the database
are model methods query set methods now imagine if you you have a model method so you know
def method self, that does some stuff, you know, accesses some attributes and then munges them
somehow. Let's say it's a full name and it concatenates the first name and the last name.
That's a really terrible thing to do because lots of people believe falsehoods about names.
But let's say that that's what you're doing.
Imagine instead of that being attached as a method onto a model, you just move it to the left one level of indentation, right?
And it becomes just a function in a module, okay?
So it takes a model as an argument and it returns a value of some sort, okay?
So that's one thing.
And the other thing is, instead of a query set method, so a query set method being, you know, model.objects.something, some custom bespoke thing that you've written in your application.
Again, move it one level to the left, indentation, have a function which takes a query set and returns a query set.
And in that function, it does some stuff to the query set, right?
So it prefetches something or it only is a field or whatever it's doing.
okay so now i've got i've got my business logic and instead of being it bound instead of it being
part of a model or part of a query set it's just a function okay what can i do with those functions
now i can put them in a data structure so if i if i said imagine a two tuple and the first item in
the two tuple or is it tuple i don't know how do americans pronounce it tuple tuple tuple tuple
i was i call it a tuple i've either i said tuple but you know you say tuple i said tuple
let's call the whole thing but i've heard smart people say both so a structure with two items in
it anyway so the first the first item in the two tuple is the query set function so the thing that
takes a query set and returns a query set the second item in the two tuple is the model function
the thing that takes the model and returns a value so what you've then got is you've expressed
a dependency between those two things.
So what you're saying is in order to efficiently call the model function,
you have to have first called the query set function on the query set.
Okay, so does that make sense?
So once you've got that structure, two things,
you can then compose those into big trees of things, right?
So you can have lots of query set functions
and you pass the query set through each one
and each one does its thing each one sort of you know modifies the query set in some way
and then you evaluate your query set and you then iterate over the query set and call each of the
functions that returns the values and it kind of i'm skipping some of the details deliberately
because that's a little bit hard to explain go and read the readme um okay so now we've got a
way of expressing these kind of dependencies between between business logic that operates
on an instance and business logic that operates on the query set well now I've got that I can go
and build serializing serialization spec mix in again right all I need to do is to take my list
of strings and I need to let's say let's say we're doing books and in that list of strings is title
all i need to do is replace that title string with a pair that has a thing that says to the
query set hey i need the title field and another thing which says go and get the title field off
the instance right so all of a sudden you have this kind of elegant way of building the thing
that we had before but was a bit gnarly um and what it what it sort of suggests is a slightly
different way of structuring your business logic in Django projects so instead of putting things
like I say instead of putting things on models and instead of putting things on custom query sets
you just write functions you can put those functions wherever you want in your code base
we have a kind of emerging standard of where to do that but it allows you to then only import
the things that you actually need to actually you know call that view you import exactly the the um
bits of functionality that you need and then you assemble them together using one of these specs
and then yeah it efficiently queries the database and and serializes the objects and you can do that
before you pass off to the render function say so that you know that you've got you've got exactly
the fields that you wanted from the database you got them in a in a the minimum or close to the
minimum number of queries possible and you're not going to cook um you're not going to cause any
more queries when you render the template or the serializer or or well or to cast it because you
you get back a dictionary right you get back a something that's json serializable yes yeah so
that that's the idea it's sort of i guess solving two birds with one solving two birds with one
stone that doesn't make sense uh solving two problems at the same time um having efficient
and and high performance views but also having um you know better ways of structuring code in
a django project yeah i mean and it's i mean do go and check it i love that discussion because
i'm beginners who read my books and stuff often ask kind of what's what's advanced django look
like and i often say it's going to be all about query sets um and i think your description just
proved that i i couldn't agree more i think i think the orm is by far the most important bit
of django you know like you can imagine almost any other bit of django looking kind of different or
replacing it with something else but the orm is really the bit which is most of the complexity
and most of the power is in there yeah i mean there was some talk about wrapping django in a
service layer um a couple of years ago or a year or so ago there's some blog posts went back and
forth and one of the points is but if you're not but if you're not using the jet the ORM like then
why are you using Django you know like you might you might go somewhere else if you weren't going
to use the ORM. I and I completely agree with that you know I think that that part of I mean
Django readers I suppose is starting to slightly go in that direction of sort of being a little
bit like a service layer but very deliberately I wanted to keep it very familiar to Django
developers so that the whole idea is that you can mix and match it with what you already know
about django it's not it's not hiding django away it's still very much django it's just doing it in
a slightly different different way i suppose and what's really nice about is the composability
it's like you could define the individual um bits to pull pull the fields out or the individual
query set um methods and then they just slot together like little legos it's lovely yeah and
And so you kind of described this, you mentioned the G word, GraphQL, before.
So you're using this to build what nice nested response is that a mobile client can get all the data it needs in a single go and that kind of thing.
Yeah, exactly.
Yeah, so we tend to try to put as much business logic as we can in the back end rather than in the front end.
You know, we try and keep our front ends quite minimal to the extent that they can be.
So we do end up with quite complex and quite bespoke API endpoints.
So I suppose we're maybe veering a little bit away from that restful purity of having very basic sort of flat representations of things
and moving more into this API endpoint serves this particular purpose.
It allows this page in the app to render, I guess, rather than the front end having to make millions of API calls and stitching them all together again.
Yeah, I mean, one thing we talked about when we had Carson, who's the HTMX creator on, was that it's kind of easier for the back-end developer to craft the API endpoint than it is for the front-end person to, you know, that you've kind of got a mismatch where the front-end person is like, I need this field and that field and that field.
It's much easier for the back-end person to put that together and say, look, here's your endpoint for that page or that request.
Yeah, exactly.
Exactly that.
Jamie, do you have any other great open source packages that you want to plug while you're on?
Because those are the two I'm excited about, but what else have you got?
Well, I find it a bit of an alien concept to plug open source packages.
I don't care if anyone else uses them.
Okay.
Well, what's on your lawn that you give away for you?
Sure, sure.
So we very much, we have an approach of open sourcing general purpose utility things, which are useful to us.
And if other people find them useful, then that's great.
So a couple of other things that we have, we have a project called Django DBQ, which is if you like a kind of lightweight replacement for Celery, you know, Celery really does two, I suppose you would use Celery in two places, very, very high performance, high throughput, highly parallelized, dealing with millions of jobs as quickly as you possibly can.
well fine but a lot of people don't really need that really all i want to be able to do is to
send an email when you press a button but not have the person have to wait until the email's
been sent before it comes back right i just want to ditch it into a queue and and kind of i don't
care unless there's like 10 10 jobs a day sort of thing precisely yes yeah so django dbq is a really
lightweight um entirely orm backed queue uh which just kind of it presents its worker as a as a
management command so um you just you know manage.py worker worker will start up and then you
can just create um instances of a job model and you can pass them some arguments and a function
to call and it'll call the function and do the thing and then it and then it's done so we use
that a lot on all of our projects and and we don't currently have any projects at all which use
celery which there's nothing wrong with celery but it's a very big complex beast and it's quite
operationally complex sometimes it's like using a sledgehammer to crack a nut
exactly yeah yeah yeah and then our other probably our um our most popular open source package is
called django log request id which is popular because it's linked to from the heroku documentation
although they they specifically link to like version 1.0 which is from years and years ago
which is a bit annoying i don't really know who to contact i don't think anyone's work there in
four years i mean with all seriousness i mean their build pack is four years old yeah or the
jango heroku thing that they linked to in their docs that kenneth worked on has been closed for
three years yeah yeah we use we host all of our stuff on heroku and it's absolutely fantastic but
it doesn't change very much it seems to be pretty you know it works and they don't
do much in the way of maintaining it um so yeah what django log request id does is very simply
allows you to every time you write a log message it will attach a uuid to the at the level of the
request so if you've got a concurrent environment with lots of requests happening all at the same
time and you're capturing the log output from that it can be very difficult to tell with lots
of interleaved log messages from different threads or different processes how they join up with each
other so what django log request id does is it sticks a uuid um in all of the log messages that
have come out from a single request so that you can then grep your logs or search your logs for
that uuid and that will give you a nice list of all of the log messages that that request created
which is which is really useful okay so that's like we have a few other sort of yeah we have a
few other small open source packages that do various simple things but they're the main ones
i think and the other thing you've got is a and there's a dab act blog as well which i you know
there's um article of tom's on there from years ago about um wrapping your django logic in a you
know manager methods and whatnot this is one of your canonical blog posts it's no it's just like
oh wow i will i will keep mentioning that blog post till the universe here we go it probably
directly contradicts the advice that i just gave in django readers no don't do it like that anymore
Well, it's about, I think the essence of that particular post is about having a single point of control for, say, creating a model instance so that if there is business logic that needs to be applied, it's applied inside that method and then all client code can call that one method and then you know it happened.
Whereas if you, in a view, if you just go, you know, model, new, dot save, model, dot save, who knows whether the business logic got applied because it's, you know, it's a bit wild west at that point.
I think that's the long and short of it, but, you know.
It is, exactly.
And we still follow that principle.
You know, it's not exactly the same to the letter, but, you know, general principles like that, you're absolutely right, are very much worth sharing and will improve everyone's Django code bases, I think.
There's lots of super posts on the Dab Apps blog,
so worth having a look at.
I should probably write some more, shouldn't I?
Yeah, no, well, this is kind of what I'm getting to.
We need to keep that going.
Yeah.
Speaking of improving your code base, testing.
Can I ask just what your kind of default testing kit
you throw at a project is?
Yeah, so we're maybe in the minority
in the sense that we just use what Django gives us.
So we use Django's testing base classes,
you know, test client, all that stuff.
We don't use PyTest.
We don't use anything like that.
Again, mostly because it's all just there in the docs
and it's how it tells you to do it.
And so it's really easy to just point people at that
and say, there you go, you know, do that.
We use a few things on top of that.
So we use model bakery to kind of create model instances.
We obviously use the sort of the built-in mocking stuff
off um but yeah basically just just django i mean a lot of the test cases come with helpers right
you know the transaction test case and these kind of things yeah yeah yeah i think that's great yeah
i mean i've been i i ask just because great to share with others and that's something that comes
up if we're you know having a beer i'd ask you and also i often in my books like i have a quite
a lot of testing um but i haven't yet gone down the pi test coverage um you know everything else
rabbit hole um because it is a lot more um it's it's used a lot it's helpful but it is you know
what you said with celery it's like well it's this whole other ecosystem we're rolling in and
um and it is true that you can get i mean i can test all the stuff i do for people just with the
built-in tools yeah i mean it's a bit weird because it's that whole you know it came out of j unit and
it doesn't it looks weird right it doesn't look like python code but somehow i was thinking about
this the other day somehow i kind of like it because you know that you're looking at test
code right rather than looking at business logic code because it's all it's all slightly weird
python with like you know uppercase camel case methods and things like that um so it doesn't
bother me weirdly i can never probably should i can never remember the name of the asserts though
i'm always like uh self assert what am i starting now like oh i you know i've been doing django for
12 years or something like that and i still keep the docs open all the time you know it's it's just
it's a big library isn't it so there's a lot of surface area to memorize so running a large agency
i'm curious how you train up your devs like what are do you do pair programming do you have internal
stuff do you have other resources you like to use because you know you you bring in more junior
people um what does that process look like yeah so we we have a few different things that we do
um the starting point for people who've never really done any django before is is always the
django docs i think that the the tutorial in there is is good enough um and that's a good place for
people to start we have an internal uh company handbook which we call the dab apps docs which
sort of builds on top of that and says you know given that you understand basically how django
works this is how we do django um so it just has dab apps specific stuff and it has a load of other
things in there around how we run the company and um uh you know front end stuff and testing stuff
and operational stuff and and all that kind of thing um and then yeah pair programming uh mentoring
um it's it's been quite difficult onboarding people uh in the past couple of years with
everyone working remotely because it's so it's so great to just have a new person and an experienced
person just sitting next to each other at a desk and you know shouting questions at each other but
we've we've adapted and we we try and have people on on zoom calls as much as possible and now we
are able to go back into the office to some extent we try and encourage new starters to go in at
least a bit of the time and um and sort of you know work with the person who's trying to to
onboard them i mean that's one of the things having someone who's more experienced who's
also interested in mentoring you is you you can't put a price tag on it i mean i think
on some level that's why all these CS grads can go into these large organizations and
it's not that the organization itself has great training I would say it's just that there are
experienced people and there's sort of there's enough slack that they can spend the time to
level you up because if you sit next to someone who knows what they're doing you know in three
months they'll get you what would take a year on your own. Oh yeah and we really try and encourage
a culture of asking questions that to me that's absolutely key it's far better to
risk appearing stupid and of course there's no such thing as appearing stupid like people
who've been programming for their entire lives are stupid questions it's just how programming works
but if you can get over that that that fear of of asking a silly question it's so much more
efficient than going away for a week and trying to figure out something for yourself and coming back
with probably the wrong answer but certainly an answer that someone solved before 100 times and
you could have fixed it in 10 minutes if you just asked and i think code review is really important
as well i think we use github and we use pull requests and and we make sure that everything
gets reviewed before it can be released to clients and and that's definitely not a sort of command
and control hierarchical thing it's not more senior people reviewing more junior people's code
it's also junior people reviewing senior people's code and that allows the juniors to see how
seniors think and to read code written by someone with more experience than them
and i think that's that's really helpful as well yeah i mean i would say as people move from
beginner to intermediate level programming specifically with django it's learning where
that line is in terms of how long do i spend on something and then when do i ask because i think
as a beginner, you know, a beginner needs to put in some degree of work, but, you know, don't spend
a week on something that, you know, maybe it's an N plus one issue, or maybe it's just, you know,
a simple config thing. Um, and I mean, I still do that. I just, just yesterday, I, I had a question
around forms and views and I did enough research that I was like, okay, I think I kind of know,
but I still want to know what the best practice is. So I asked Carlton, asked some other people
And, you know, obviously, like, I sort of know what's a good question to ask someone.
But to your point, I still ask all the time around certain things.
But it's usually more, you know, what's the best way rather than, you know, how do I get this to work?
Because I can get it to work.
But do you want to give a plug, Carlton, to rap reviews?
Just because I am throwing it in the 3.2 update to my books.
But it's something close to your heart.
So the question Will asked yesterday was about, say you've got a view that you want to respond to differently to, I don't know, something on the request.
Like, you know, it might be the content type.
Like a detail view of the form.
Yeah, okay.
So you want to handle the detail view and the form view in the same thing.
And then, you know, so you can have a nice two separate views, one that just returns the detail view and one that handles the form.
And then you can have a kind of view that decides which to dispatch to in front of them.
It's kind of a nice pattern because you can do that with a list view
that you also want to be an RSS view or JSON response for the same thing.
And it's a nice pattern.
I was like, no, Will, do include that in the example
because I think that's something that's really handy to learn is this.
Because if you put it all in one big fat view, it gets really complicated.
I'm a really big fan of simple views.
i have to confess i'm not a huge fan of django's generic views django's well django's kind of class
based views i guess um to me i there's there's a fantastic uh quite short book um written by
luke plant called django i think it's called django views the right way that's a really really
good read and it kind of argues that the way django views encourages you to compose complex
functionality is quite confusing quite difficult to follow quite difficult to read and you only
can really follow it if you know the api really really well or if you kind of almost have the
source code open next to you so you're kind of going okay so that method is called by this thing
that's on that base view mix in and then that one calls that one and it's just this huge nest of
things calling other things and often it's just easier to write the damn code out you know
even if you're repeating yourself it's just clear and you can just see this happens then that happens
then that happens and then that happens done right and i'm a big fan of that exactly um i think
the class-based views are kind of as they're in they're just too clever then they're they're
they're kind of the best example i know of what goes wrong with object-oriented programming like
you know this good code it's great code it's super tested it's it's super well documented
it's got classy class-based views for when you you know when you need to use it but
that's not maintainable easy to reason about you know software carlton i have to read your tweet
because we had this exact discussion where i even said to carlton like i look i have it working
function-based views like but i really i'm i'm somewhat committed to the generic class-based
views and getting them you know tweaking it properly and carlton said and i quote if post
loads all logic and all in one place else loads more logic and all in one place versus breaking
it up so i agree with that but that is that you know to your point yeah you are going to duplicate
yourself a little bit but you know it's weighing that versus this big inheritance chain and and
part of why you split up class-based views is that when you have a detail view and another mix in
another mix in you know that gets wonky fast with in subtle ways so but as well a lot of the mixing
methods they're like um it'll be just like um self um the object is equal to self.get object
and then that will be the sub method a single object that will be the super method that you'll
call so you'll get so in your your method you go super um you know this method and then you write
some other logic and then so when you're looking at that six months later you have to go and look
at what the super method is but the super method was one line well from that six months later you
is much better off having that one line in front of you,
even if it was duplicated,
than having to dig through two or three files
to see what's actually going on in this method.
I would argue, and Tom's argued,
and Jamie, you're nodding, so you clearly agree.
I completely agree, yeah.
Come on, let's do our weekly plug
for Django Vanilla Views as well then,
because Tom Christie wrote this alternate set
of class-based views called Django Vanilla Views,
which is a nice example of a different way
of implementing the same functionality
but in a more sort of inline declarative manner.
Yeah, and again, Django Vanilla View
is another thing that Tom was working on
when he was at DevApps
and I seem to remember he wrote a blog post about that
which is probably still on our blog as well somewhere.
As we wrap up, I always want to ask about deployment.
You mentioned you use Heroku.
Are you using GitHub Actions
or what's the standard flow for deployments for you all?
Okay, so we very much try to keep our sort of
ops and deployment approach simple
and I don't like running servers.
I've done it for a long time
and I think that it's a big overhead
and you have to almost hire a team of people
to do it properly, you know,
with the proper security patches
and keeping things up to date.
So we use GitHub Actions for CI.
What we do is kind of,
we work in a pull request workflow.
So we'll have, let's say that we have a project
that's been live for a while
and we're working on a new package of work
that might consist of, I don't know, three features and two bug fixes.
Each one of those will go into its own pull request
against the main branch.
Each one will be reviewed independently.
We'll then build what we call a release branch,
which is essentially another pull request
which merges all of those together.
And that's another pull request into the main branch.
That will then get deployed to a staging environment.
And in order to do our deployments,
we just use the heroku web ui you know we we go in and we have a rule where we we pair on
deployment so you always have two people making sure that you're clicking the right button on
the right project kind of thing but you um yeah you know you you go in you press the button it
deploys it to the staging environment you test it internally the client signs it off and then
same process for deploying to production click a button and i'm i'm very keen on that approach
definitely sounds rock solid to me just always like to ask anything else you want to bring up
well i mean all i would say is um we're always on the lookout for good django people in the uk
so if there's anyone who fancies working in a an environment with a lot of knowledgeable django
people doing an interesting mixture of different types of client projects you know we really don't
specialize in any particular type of client we have all sorts of different projects in completely
different sectors all going on in parallel at the same time so it can be really really interesting
so if anyone is interested drop me an email jamie at dabapps.com um even if you don't see a suitable
job ad on our website just drop me an email anyway because we're always on the lookout yeah fun okay
super well i'm gonna say thank you for coming on like you know really really exciting um to
talk about your projects and really interesting on you know i'm so hyped about jango readers and
you know i bumped into it a little while ago and there was an issue that was is this usable
in production which you recently closed as yes 1.0 yes i tagged it 1.0 we're using in production
so that means that everyone else can okay super well that's that's honestly that's that's really
good to hear because i think you know i'm always slightly concerned that ideas that i have are a
bit crazy and so to hear someone else who's very very knowledgeable about django thinking that it
might be a good idea makes me very happy so yeah no i mean it looks it looks right in the in the
ballpark you know there's there's caters there's attas and caters it's pedantic there's you know
and in my sort of project folder django readers now is in there as like you know these are these
are the contemporary approaches to serialization so super i'm excited to be that's a good tagline
a contemporary approach to serialization that's trademark me right anyway let's call it quits
jamie thank you for coming on thank you for joining us everybody um we're uh django chat
dot com and chat django on twitter join us next time bye bye thanks jamie thanks bye