Do you write web apps in Django?
The framework has come a long way lately, with versions 3 and 4 adopting many of the modern Python capabilities.
Async, for example.
But there are so many other libraries and apps that you can use to do more with less code and plug in new functionality.
I'm happy to have Christopher Trudeau here on Talk Python to take us through his 17 favorite libraries you should be using in Django.
This is Talk Python to me, episode 379, recorded August 22nd, 2022.
Welcome to Talk Python to me, a weekly podcast on Python.
This is your host, Michael Kennedy.
Follow me on Twitter where I'm @mkennedy and keep up with the show and listen to past episodes at talkpython.fm.
And follow the show on Twitter via at Talk Python.
We've started streaming most of our episodes live on YouTube.
Subscribe to our YouTube channel over at talkpython.fm/youtube to get notified about upcoming shows and be part of that episode.
This episode of Talk Python to me is brought to you by the IRL podcast, an original podcast from Mozilla.
This season, they're looking at AI in real life.
Listen to an episode at talkpython.fm/IRL.
And it's brought to you by Microsoft for Startups Founders Hub.
Get early stage support for your company and build that startup you've been dreaming about.
Visit talkpython.fm/foundershub to apply for free.
Transcripts for this and all of our episodes are brought to you by Assembly AI.
Do you need a great automatic speech to text API?
Get human level accuracy in just a few lines of code.
Visit talkpython.fm/assemblyai.
Hey all, a quick announcement before we jump into the interview.
Some of the ideas we discuss in this episode come from a brand new Django course that Chris authored over at Talk Python Training.
If you enjoy this episode and want to put these ideas into practice or you want to just get started with Django,
be sure to check out his course at talkpython.fm/Django.
Now let's dive in.
Chris, welcome to Talk Python to me.
Thanks for having me.
Yeah, it's great to have you here on the show.
You know, we've worked on some projects together and talked otherwise, but your first time here on Talk Python.
Monumental.
Indeed, indeed.
So I'm super excited to talk about Django.
I don't do that much Django, which is why you're here because you do a ton of stuff with Django.
So really excited to have you share your experience.
And we're going to focus on a bunch of cool little tools and apps that you can plug into Django and make it better,
make it do more and do a lot of the Django things, you know,
pull a few pieces together and make your app better without a lot of coding, right?
That's the idea.
Indeed.
Before we get to all that, though, let's just start with your background.
How do you get into programming in Python?
I'm an old man, not punch card old, but single digit megahertz old.
My dad worked for IBM.
So my first computer was an IBM PC Junior.
256 kilobytes of memory with the expansion card.
No hard drive, five and a quarter floppy and 4.77 megahertz.
And that second seven is really, really important.
It made all the difference.
Did it have a turbo button?
It did not.
IBM did not do that little bit of marketing stuff.
But I'm pretty sure my USB charger has more processing power now.
But all my friends had Commodores.
And so I couldn't trade pirated games with them because that's what everyone did.
And the box came with this kid friendly teach yourself basic book.
And so that was kind of my intro.
There was I had one game and nothing else to do with the computer.
And the first program I remember writing was a Batman logo, not copying it from a book, like on my own kind of thing.
And so like the basic library had like draw arc and fill in yellow and it kind of clicked for me.
And 30 years later, I was running a software department at a company that got acquired by a large firm who shall remain nameless.
They just own all of your favorite movie franchises and have a rodent fronting it.
I think you know who I'm talking about.
And as part of that acquisition, the department got shut down, but we were asked to stick around to help with the transition.
We had about two weeks worth of work to do and we had six months to do it in.
So I had a fair amount of spare time on my hands and I used that to pick up Python.
And the first script I wrote in Python was that we had a photo sharing site and the due diligence of the transfer included looking for questionable content in that photo sharing site.
And I had to, for the police investigation, go off and grab a whole bunch of stuff out of S3 and download it that belonged to this one individual.
So the script was kind of icky, but I was very, very impressed on how little code I had to write in comparison to previous languages.
Part of that's Python itself and part of it was just, you know, pip install, pip install, pip install, and it solved all these problems.
And I've never looked back.
It's been my primary language for almost 15 years now.
What a good language.
What a good choice.
Who knew 15 years ago or 10 years ago or whenever we all got into it that it would be so incredibly popular these days, right?
Yeah, it's grown a lot.
It's, yeah, it's really taken off.
Yeah, I just saw an article.
What was it called?
The Unstoppable Programming Language or something like that from InfoWorld.
And boy, it, I'll even pull it up.
What an interesting situation where, you know, the subtitle of the article is Unstoppable Python.
Once again, ranked number one in the TOV index.
I think it's the breadth of the libraries, right?
Like most of the languages, there's, you know, JavaScript is often at the top of that list, but it's only really for one purpose.
It's for building web applications.
And I know you can do other things in it and not trying to upset the internet.
But with the data science behind.
You're going to get us email, Chris.
Oh, yeah, I'm sure.
Well, you'll get them email.
I'll be long gone.
So that's fine.
With the data science side, with the ML side, with the, you can do things on the web side, right?
Like there's being number two in all of these areas very easily makes you want number one overall, right?
So it's, I think it's the breadth more than anything.
Yeah.
You talked about how the company around was acquired and you had all this sort of time to kind of think about changes.
I find times like that are really interesting ways to maybe refocus your career or to think about where you've been and where you might be going.
Maybe whether you should turn left or right or just keep going the way you are.
You know, I've had a few like that.
And it's, those are some good opportunities to take if you can get them.
Yeah, it gives you a chance to experiment if nothing else.
You know, there was no pressure to pick up a language.
I was a manager at the time.
So there was no pressure at all, period.
But yeah, it gives you the breathing room to go and play with a few things and get comfortable with it.
And the next job I took was helping a small startup.
And a manager comes to me and says, oh, pick the language, pick the stack.
And I was like, okay, we'll do Python.
We'll do Django.
Then it sort of went from there.
So good choice.
How about now?
What are you doing these days?
My marketing people tells me, tell me I'm supposed to call myself a fractional CTO.
So I help organizations with technical decisions and software processes.
So that's architecture, some coding.
Often it means nowadays the agile process stuff.
So it's a bit of a mixed bag.
I tend to specialize in trying to get small teams more efficient in some tech way, either the process or the learning itself.
And because of the agile thing, I've done a fair amount of teaching.
Because oftentimes when you're bootstrapping new teams, you got to start out with Scrum 101 and all that kind of good stuff.
And that kind of led into the screencasting and online teaching world.
So now I've done over 30 courses in Python and I'm still clicking along.
So it's become this sort of side thing that I have that has blown up into its own thing.
I can relate.
I can definitely.
It's awesome.
Well, cool.
So part of that actually is you and I just recently worked on a course for Talk Python training, Django, getting started.
Which there's been, you know, it's a six hour course.
People can check it out.
There's a bunch of good stuff.
We're not going to really talk about that.
But it kind of got me thinking like, hey, wouldn't it be great to just cover all the cool little things that you touch on here and then just, you know, in your other training.
I guess people probably could reach out to you if they've got a team and they want to maybe help them shift gears, help them change technologies or change the way they're working.
Sure.
Always nice to have the pipeline full.
So for sure.
Indeed.
Yeah.
So, you know, you always, you might be brought in to do one thing like, hey, help us do Django or help us change the way we're working with sort of deploying our apps or whatever.
But then there's like, oh, but did you know about this tool?
And have you tried this?
And wouldn't it be easier if you use that?
And so how about we make that the next hour?
Yeah.
You know, and this kind of ties back to that.
You know, we were sort of talking about Python and the breadth of that, right?
One of the reasons it's so easy to get a lot of things going is because there are so many libraries that have been there and done that.
And I often, we're going to talk about later, you know, one of the ones that's sort of a catch all.
And every time I'm in there, I'm like, oh, oh, wait, I need to remember that's in here because I keep writing that code.
Right.
And so knowing that things are out there and finding this stuff can make a big difference in how little code you have to write.
And it's always great when someone else has tested it, because then not only are you not having to write it yourself, but it's probably more stable than the stuff that you're writing yourself.
Or at least I'll speak for myself.
It's more stable than my code.
For sure.
Well, I think, you know, people who are getting into programming think about what is an expert.
An expert is somebody who could write these crazy algorithms or implement this wild file processing stuff from scratch.
And that somewhat is true.
But more often, the expert is the person that knows they can pip install this other thing and not have to write that.
You know, they're like, oh, these libraries exist.
I know they'll work in this situation.
I don't need to do this.
Right.
So, yeah.
It's both a power, but it's also really like knowing Python.
I think knowing Python is partly knowing the libraries outside just the language.
I would say more than partly like picking up a new language is if you've done a few before and it's in the same vein, although, you know, all the grandchildren of C based languages.
It's like, OK, so how do they what's variable assignment look like?
What does four loops look like?
Once you've done that, you know, a few days later, you're ready to go.
Knowing the depth of what's out there so that you don't have to write it, that takes forever.
Right.
So, you know, there's language expertise within months.
There's library expertise, which is years and is constantly changing.
It's nonstop.
It's like you can't learn them as quickly as they come out, really, especially if you're in JavaScript.
That's another story.
Yeah, I saw a funny T-shirt that said I learned Python.
It was a great weekend.
And that's in some sense true.
Right.
But on the other, you'll compare and contrast that to like, I feel like I've been doing this forever.
And I'm still learning every single day.
How do you square those two things?
Right.
It's a lot largely what you just said.
Yeah.
All right.
So we're going to talk about a bunch of different topics.
We'll see what the final number is.
17 ish different libraries, some of them directly pluggable into Django for specific things,
and some of them just really helpful for Django.
So you want to kick us off with the first one here?
So there's sort of two groups in the first group of things that we're going to talk about are libraries that any project of a reasonable size should consider using.
So these are like you said, these aren't the Django specific stuff.
And then we'll get through a few of those and then we'll get into the actual this you should use this for Django.
So this first one that you've got up on the screen there, this is coverage.
This measures how much of your code gets run when you run your code.
So it's typically used for your user tests.
And what you're trying to figure out is how many how much of your code has been exercised when you run your tests.
So it has sub commands, one of which is run, and you basically hand it any script and it will give you a output listing of what it saw as it went along.
That output listing is like a file by file listing and shows you like a percentage mark that says, oh, you know, 30% or 50% or whatever of this file got executed in your run.
And then there's a couple other commands that you can run that will combine all this information into a report.
And the report is spit out in HTML and that gives you a fully annotated list of your code.
So you can go in and see, oh, there's the red line.
That's a line that didn't get triggered.
So often I find when I'm writing tests, it's usually fairly easy to get the, you know, the easy path through, right?
You're not thinking about the errors or whatever.
You just sort of, oh, I exercised it.
And then you go, oh, I've only got 75%.
Well, finding if you want that, you want to have something higher than that.
You go in, you look at the report and you go, oh, that red line is that error condition.
Okay, I need to add a test to make sure that that error condition is handled properly.
So I often take this one and then write a little bash script that does this, runs my tests and then runs a linter afterwards.
So it's my little check-in hook, right?
So just before I do a push, it'll go off and run all my tests and give me coverage.
And if I don't like the numbers, then I go off and fix it some more.
I think when you're learning about testing, it's important to test the happy path, but that's the one that often kind of obvious, right?
You're going to know right away if that thing is broken.
But it's those edge cases.
What if I put a string into this input where, you know, a number like the word seven versus the number seven?
Is that a 500 server error or is that a, sorry, invalid data, ideally even caught on the client side with HTML5 validation or something?
Those kinds of things are really hard to think about.
And coverage really points out, you know what?
All the parts that are read that are uncovered, those are the error handling or the guarding clauses or the other cases where you're not normally going to run into them.
So you really need to have a test to check them.
Yeah, that's right.
I'm also independent of coverage.
I'm also a big fan of when bugs show up.
I'm not a pure TDD guy until bugs show up.
So when the bug shows up, I go and write the test that triggers the bug and then I fix it because then I'm adding to my regression test as well.
Right.
So that's also to your point, it's those weird conditions that you didn't even think of.
And coverage, because it is only line based, you can get into trouble where, you know, the first part of an if clause passes and the second part doesn't.
And so it's green.
It looks like it's happy, but that doesn't mean you don't have a bug.
Right.
So there's always this mix and go.
But coverage can help you find this stuff first time through if you're looking.
I'm definitely not a purist, TDD purist myself either.
I find there's tests add a lot of value, but there's also a practical, I just got to get some stuff done and I don't need to like retest everything.
It'll only so many hours in the day.
Yes, exactly.
But I do like this idea of like once you found a bug, if you can reproduce it with a test, you kind of pin it down so you don't play whack-a-mole and have it ever come back.
Exactly.
Yeah.
Kind of related to this whole part of the conversation, Anthony in the audience asks, he's interested to know how best to test Django web apps with pytest.
Feels that there ought to be ready-made recipes for this, given how opinionated Django is.
You got any thoughts on that?
I don't actually use pytest myself, so I'm only vaguely familiar with it.
There are some recipes out there.
I know there are Django apps that you can install that will help you and pre-canned with the recipes.
Django is fairly robust itself.
It builds a whole bunch of things on top of the unit test framework that is very Django specific.
And it allows you to shortcut the web as well.
So you can access the views directly, which means you don't have to worry about like a lot of JavaScript and things like that.
And it also has a live server mode, which I was playing with this afternoon, actually, which runs a server so that you can run things like Selenium on top of it.
So there's a fairly rich set of mechanisms in there for Django to begin with.
From what I understand of the pytest library, it really just sort of makes some of those hooks easier and exposes them rather than introducing a lot of extra functionality.
For sure.
Wouldn't you know that there's an awesome Django list?
And it happens to be done by Will Vincent.
In here, there's a whole section on testing.
And you've got some pytest Django.
You've got Factory Boy for test fixture replacements.
A feature flipper Django waffle.
That's kind of an interesting name.
Model Bakery for creating, I'm guessing, the ORM models in interesting ways.
And yeah, people can check this out.
Another related question, Nick asks, I like to hear opinions on mocking the ORM database when testing versus actually using the database.
I don't know how you feel about this, Chris.
I don't tend to mock unless I absolutely have to.
I usually mock for things like, oh, we have to do something with dates.
And dates and times always cause problems because, you know, you're running the test now.
For the ORM, I tend to just use tests straight into the ORM.
Django comes with a lot of mechanisms like fixtures that allow you to push things into the database.
And the test suite automatically will install those fixtures and wraps each test in transactions.
So it does it and then undoes what you did.
So you're always in a known good state at the beginning of each one of your functions.
So I haven't really come across a case where I really need to mock out the ORM.
I would guess there's probably a argument about speed there.
But I tend to get around that with things like tagging my tests.
So I will tag much that are like the smoke test, the quick one pass through.
And if I need like a really fast test to run on, say, check in, then use a smoke tag and then let the regression run overnight if I have to or whatever.
So I haven't come across the need for mocking it out yet myself.
Yeah.
And you can use SQLite with an in-memory database model as well.
And just as start of the whole test run, you could fill that in-memory version up with known good test data.
The transactions will kind of roll it back each time, right?
And so just let it rip on SQLite in memory and then disappear into the ether of RAM.
Yeah.
It tends to be, unless you're doing huge amounts of work, it tends to be pretty peppy.
Sure.
Yeah.
And you can choose how much data you put in it, right?
So you can chill out on that.
This episode of Talk Python to Me is brought to you by the IRL podcast, an original podcast from Mozilla.
If you're like me, you care about the ideas behind technology, not just the tech itself.
We know that tech has an enormous influence on society.
Many of these effects are hugely beneficial.
Just think about how much information we carry with us every day through our cell phones.
Other tech influences can be more negative.
I really appreciate that Mozilla is always on the lookout for and working to mitigate negative influences of tech for all of us.
If those kinds of ideas resonate with you, you should definitely check out the IRL podcast.
It's hosted by Bridget Todd, and this season of IRL looks at AI in real life.
Who can AI help?
Who can it harm?
The show features fascinating conversations with people who are working to build a more trustworthy AI.
For example, there's an episode on how the world is mapped with AI, but it's the data that's missing from those maps that tells as much of the story as the data that's there.
Another episode is about gig workers who depend on apps for their livelihood.
It looks at how they're pushing back against algorithms that control how much they get paid,
and how they're seeking new ways to gain power over data and create better working conditions for all of them.
And for you political junkies, there's even an episode about the role that AI plays when it comes to the spread of disinformation around elections.
Obviously, a huge concern for democracies around the world.
I just listened to The Tech That We Won't Build, which explores when developers and data scientists should consider saying no to projects that can be harmful to society,
even though we do have the tech to build them.
The next thing kind of related to that is PyFlakes.
I mentioned at the end of that that I often use a linter.
This is the one that I tend to go to.
PyFlakes is code-focused rather than style-focused.
So when I first started linting Python, a lot of the code I was maintaining was not PEP 8 compliant,
and we'd run the linters and they were just constantly screaming about everything.
PyFlakes was like a nice little happy medium for us.
It runs using the abstract syntax trees, which means it doesn't actually load the modules, which is good because that means you're not having to do the side effects of your actual code.
And I usually use it for things like finding unused imports and weird variables and things like that.
The other place is I find if I've made a lot of changes across a whole bunch of files, running PyFlakes before I run my tests, it's sort of a bit of an idiot check, right?
So the things that don't compile or whatever, it'll go through and run everything once for you.
And it seems I find it faster to do that than, say, run all my tests first.
Sure.
This is kind of like a compiler, you know, and compiled languages, C++, C#, Swift, whatever.
You press compile and there's a how does it all hang together sort of check that the system has to go through as a static language.
And we don't have that.
Even if you put type hints, that's a hint, not a requirement for accuracy.
And so not saying that this does, you know, type validation like mypy, but it makes sure that your code at least somewhat hangs together, right?
It's a nice, nice quick check.
Yeah, it's a sanity checking.
Yeah, absolutely.
And there's a version of this, if you want to dig down into it, that is called Flake 8 that combines PyFlakes with PEP 8.
So if you want to get all anal retentive about the code cleaning and all the rest of that, you can dig into that.
And essentially, it's just called the same kind of commands after it.
Also has a nice little, one of the things I always look for in a linter is the pragma that says ignore this line so that you can turn off the noise.
Because every once in a while, there's going to be something that you want it to ignore.
And I find as soon as you've got warnings popping up in your code, it starts to become broken window theory, right?
Like, oh, there's a warning there.
Oh, now there's two warnings there.
Now there's three warnings there.
And the next thing you know, you've got 100 warnings and nobody's doing anything about them.
So I like to try.
That's exactly the analogy I was thinking as well.
And that's the way it is.
Because especially in a team situation, you know, there's some people who are really bought into like CI and that kind of stuff.
There's other people who are not really that interested and worried whether the test still passed or worried about whether the linters pass.
And they're just going to go along.
But certainly if that kind of stuff starts showing up, they're like, well, if it's already got warnings, I don't care about one more, you know?
Yeah.
So the zero warnings policy is pretty good.
And this kind of thing helps you find that and check it easily.
Right. So for people who are listening, you just put hash for comment, Blake 8 colon no QA on a line and then it'll skip that line.
You know, there's times when you get advice that in general is good advice, like try accept past or something like that.
You should never do that.
Except for sometimes in little weird situations, you're like, no, I really just need this to not care if there's an error and just keep going.
And we're just, you know, stuff and you'll you'll be stuck with this permanent warning.
This file has an error.
You're catching too broad of an exception.
Like in general, yes.
But right now I don't care.
I accept that.
Let's just keep going together.
Yeah.
And this kind of stuff really is great for making those warnings go away.
And you can tie it into your PR process as well.
So if I'm doing a poll review for something you've done where you've put this, we can have a policy that says there better be a comment above it that explains why you're allowed to ignore it in this session.
So it becomes sort of two kinds of flag.
It's a flag for pie flakes.
And it's also a flag flag for your code reviewer to go, oh, we should explain why, you know, is this a valid case?
Oh, yes, we do.
This is this is the generic.
So let's put a comment that says, yes, we meant to do this rather than I was just too lazy to fix it.
Yeah, that's a really good point.
Actually, I like that a lot.
All right.
On to another Sphinx, the Python documentation generator.
Yeah.
So this is a sort of bit of a left turn here.
I will admit I am obsessive compulsive when it comes to comments and documentation.
I did co-op in university, which is what I think they call paid internships in the US.
And my third co-op term was with the same department as my second.
And the first day back into the office, I said hello to everyone.
And then my boss says, yeah, there's a bug in the code you wrote last term.
Go fix it.
And if my name had not been at the top of the commit, I would have sworn this was written by somebody else.
The code was just hideous.
And this is where I learned the whole comments are for other people is only half right.
Sometimes you're that other person like eight months later.
Just shifted in time.
Yeah.
So I've become very, very, very retentive about it.
And so what Sphinx is, is a mechanism for taking your PyDoc comments and turning it into documentation.
And so if you were writing your comments already, it gives you a couple little formatting tags that you should take advantage of.
But once you've done that, it's a lot of effort.
So I've got a lot of effort to take advantage of the code.
And so I've got a lot of effort to take advantage of the code.
But one of the things I find I use a lot is you can highlight references to other parts of your code.
So if I've got a class that I'm using here, an object that is some sort of class, if I note it properly in the comment, when the documentation is created, I can click a link and it'll take me through to it.
So you can always find the cross references.
Yeah, that's fantastic.
Generates all sorts of different kinds of output.
I personally only ever use the HTML, but it does EPUB, ManPages, LaTeX, if you want to spit out some PDF and some other things as well.
Comes with a sort of a quick start command that builds all your cookie cutter files for what you need.
It also allows you to intermix in general RST files.
So if you want to write, say, a how-to guide separate from your code, but then suck in some documentation from your code, it allows you to mix and match that.
So as an example.
Tutorial or installing or something like that.
Yeah, so I often will write, although Markdown is the most common format for the readme file on GitHub, I use readme.rst.
And the reason I do that is because I usually use that same readme file as the intro file in my Sphinx doc.
So I essentially just say, oh, go grab that readme.rst, pull it in here as the title page, add a little table of contents flag on the bottom of it.
And the next thing you know, you've got some documentation.
Yeah, that's really fantastic.
It's great when you can get your work to multiply automatically.
And obviously, you know, you've got to have been in the habit of doing this kind of stuff anyways.
But if you were, adding a little bit of rigor to how you're writing the comments helps a lot.
And I find particularly with things like APIs, right?
Because you should be writing that doc string anyways that says this is what the call is.
These are the parameters and what they mean.
And it turns all that into a PDF document that you can, you know, hand off to managers or whatever, put up on your web page or however you like to do that.
Yeah.
For those who are not a fan of restructured text, there's the MIST markdown version or plugin.
So you can do markdown as well these days.
I have to check that out.
I haven't played with that one yet.
Yeah, yeah.
It's pretty neat.
You can even do inline restructured text within your markdown.
So you're like, markdown, markdown.
Oh, I need something a little bit more complicated.
There's a way.
I don't remember what the syntax is, but there's a way to, you know, inline a little restructured text.
Excellent.
And then fall back to markdown.
Yeah.
A little bit of an escape hatch.
And then embed your HTML inside of your restructured text inside of your markdown.
It's turtles all the way down.
Excellent.
Absolutely.
The other thing, there are companion plugins for this as well.
So one of the other libraries that I use is something called a Sphinx RTD theme, which is a read the docs style theme and plugs right in.
And essentially, it allows you to generate your HTML looking like the read the docs site.
And if you combine that with a git hook into read the docs, your read the docs will get automatically updated every single time you do your push up to git.
So nice little combination there.
Yeah, that's very cool.
I do find it sort of meta that the Sphinx read the docs theme is hosted on read the docs.
Yes.
So fun.
All right.
PUDB.
Is that the right?
I have no idea how you're supposed to pronounce it.
I always say PUDB, but that's fine.
PUDB.
Well, I do feel like a lot of these projects like this one, if you have too much of an acronym or you have too clever of a name, you really should put a, and here's the MP3 of how you say it.
Hey, there you go.
Yes.
The little, I loved that answer with Linux.
It was, hi, my name is Linus and this is how you spell Linux.
And I couldn't understand his accent.
It didn't clear anything up.
It was fantastic.
That's funny.
I think I've mentioned up front that I'm old.
So a lot of my early career was spent on Unix systems, SunSpark systems, that kind of stuff.
And at the time there was this whole war between VI and Emacs.
The war is over.
I think VS Code won.
But I picked VI because it was the only thing guaranteed to be installed on any of the systems I was telnetting into.
And so I'm still very old school using Vim to this day.
Yeah.
I mean, you just said the word telnet.
Come on.
I'm keeping it.
It was telnetting.
It was pre-SSH.
I know.
Yeah.
Now, hold on now.
Did you do like Archie and Gopher before telnet?
A little bit of Gopher.
I'd never, I was never on an Archie system.
I did a little bit of Gopher.
Yeah.
So.
It could even go more old school than that, but yeah.
Okay.
Yeah.
Great.
So maybe these days you're SSH'd in, but same basic idea, right?
Same basic idea.
So why am I babbling about this?
Well, what this means is because I use an editor rather than an IDE.
And of course there's another place where you'll get letters because you can do everything in Vim
script.
So it's an IDE as well, but I tend to just use it as a letter editor.
What that means is I tend to use a standalone debugger.
So PUDB is one of those.
It's a standalone debugger.
I'm not sure why, but I've never been a big fan of PDB.
The one that comes with Python.
Part of that is because it's based on GDB, which I never liked either.
I just need to see more screen, more code on my screen at a time.
And so this is a TUI program, which is text user interface.
And it's for, and if you want to, again, shout out to the old folks in the audience, it's
got a very Borland turbo feel to it.
So you can see the screen and the text that you're working on.
And then there's a couple little side windows with your stack and your variables and set
breakpoints, all the things you expect a debugger to do.
And if you're stopped at a breakpoint, you can open up a REPL and it gives you full context
of where you are, just like you would with inside of PDB.
So I find oftentimes I'm doing more debugging in the REPL in context than I am actually in
the debugger.
Now, why this is a big deal for me is let alone the local.
If I were using PyCharm or whatever, I can work locally.
This will work anywhere where I can SSH into.
So because it runs over the terminal, I can get into a machine.
I can use this and have it work.
And it means I'm using consistent environment across all the places I go.
So I don't try to sell this to other people.
When I manage teams, I don't say you will use this, but it tends to be my go-to.
And I like to tell people that it's out there because you never know when you have to do that
remote stuff.
Yeah.
A lot of times, you know, like it works on my machine and you get the certification even
there.
It works on my machine.
And then I go to the server and it doesn't work.
And I can't really figure out why, you know, especially when you're setting up a new environment,
you're like, ah, trying to run the web app now and micro WSGI over here and it just won't
start or something like that.
Right.
So the ability to get a little more insight over SSH is pretty cool.
Yep.
Good.
All right.
Is this, I think this may be our last sort of, nope, second to last general, general library
is talks.
Yep.
So this is a wrapper for all your tests.
So it essentially builds virtual environments based on a quick little configuration file.
So give you an example.
Let's say I've got a line that says pi brace three, seven, three, eight, three, nine, three,
10 dash Django 400.
It knows how to split that apart and we'll do all the combinations of running Python three,
seven with 400, three, eight with 400 and et cetera, et cetera, et cetera.
And it creates a little virtual environment for each one of those combinations and then runs
all of your unit tests inside of that virtual environment.
So if you're doing library support across multiple Python versions or across multiple, say,
Django versions, then you can mix and match these with just a few lines inside of a configuration
file and it will go off and run all of this.
And those virtual environments are created locally and cached.
So although the first time it runs, it's dreadfully slow because it has to pip install all of your
requirements in each one of those environments.
Once that's set up, it just leaves them there, which means, you know, first time hurts.
And after that, it's not too bad.
It's one of those trade-offs between I want an absolutely clean from scratch reproducible thing.
Yes.
Also, when I get my job done.
So if you're going to test across five different versions of Python, maybe don't try to pip install
something like micro whiskey or other things that have to compile for a great long while.
Just, just leave it there.
Because it does compile and leave it, you know, let it do it.
Go get dinner.
Come back and just never delete that virtual environment ever, ever again.
Yeah.
I suspect it has multiple levels of caching as well.
Like if I pip install something and it's exactly the same version, it'll still be cached
even on my machine, even if I recreate the virtual environment.
So probably.
There's levels of it.
It essentially just creates a, I'm trying to remember.
I think it's dot.
It might even be dot VM.
It might be dot talks.
I can't remember.
But it essentially just creates a directory and creates a directory inside of that for each
one of your combinations.
And then pip installs into that virtual environment.
So when it runs the next time, it'll do upgrades and things like that.
And if you need to, you can just go in and RMRF the directory and blow it away if you're
running into trouble and need to start from scratch.
It sounds interesting for a web app.
It sounds super useful for a library package.
That's where I tend to use it.
So we'll talk later about one of my little bits of self-promotion here.
But I've got a couple of Django libraries that are out there.
And, you know, I support 3.6 through 4.0, I haven't got around to 4.1 yet, and three
or four versions of Django in it.
And every once in a while, you'll run into something that just doesn't work in some version
that you think is generic.
And it's become a lot easier since I've dropped support for 2.7 because there was a lot more
crap having to deal with that.
But that's how you catch those things.
Yeah, absolutely.
The last general one here is Pillow.
This is semi-general.
In case you're sleepy, you're programming too long and you just need to take like a little
bit of a nap or what's going on here?
That's what it's for.
That's right.
Pillow is for sleeping.
It's also for image manipulation.
So I don't do a lot of graphics stuff.
My Batman logo, notwithstanding, was very early on in my programming career.
But in fact, Django has a semi-dependency on this.
You don't need it out of the gate.
But if you're using certain features in Django, you do have to have it installed.
There's a field in Django, which is the image file field.
And it uses the Pillow library to make sure that the files that are associated with it
actually are images.
So this is a really deep, really cool image processing library.
And I tend to just skim the surface of it.
I use it for image and I use it for a couple libraries as well that deal with image thumbnails.
But otherwise, I don't really touch it.
But it tends to be one of those things that if I go through all of the virtual environments
set up on my system, I'm finding, oh, it's installed in a lot of them.
So it's one of those that's kind of common that I, because I don't do a lot of image stuff,
it's not something that I'm playing with a lot.
But it's very, very powerful.
So if you're into this kind of stuff, this is a great library to play with.
And if you're not, you may want just the surface level pieces for some web things like thumbnails.
If you're running a website that accepts, say, image upload, for example.
Yes.
You obviously need this for the Django ORM field.
That's the image type.
But you could also say, if it's too large, let's just resize it.
Or you can resize it to the same size all the time.
You know, it drives me crazy when I go to sites where like, this image is 1500 by something
and we only support 1280.
It's like, just resize it then.
Yes.
Yeah.
I've also used it in like in some command line scripts, which will like create like two
or three versions of an image that is in the static files.
Right.
So it'll automatically go through.
And like you said, okay, we've got our master that's, you know, 1500 by 1500.
And it'll go create some extra ones or whatever.
And you run a command and it'll run through all your static files and check that there's two
or three size versions or that kind of thing.
So again, if you're playing with the web, size is important.
Right.
So yeah, for example, if you want to have icons for your web app that can be saved to
iOS home screens, you know, they want all these different sizes from like 512 down to 64.
And if you're doing retina or high resolution, you can have different ones that get swapped
in and out.
And like, it'd be really nice to just automate all that.
Right.
That's right.
Yeah.
This portion of Talk Python to Me is brought to you by Microsoft for Startups Founders Hub.
Starting a business is hard.
By some estimates, over 90% of startups will go out of business in just their first year.
With that in mind, Microsoft for Startups set out to understand what startups need to be successful
and to create a digital platform to help them overcome those challenges.
Microsoft for Startups Founders Hub was born.
Founders Hub provides all founders at any stage with free resources to solve their startup challenges.
The platform provides technology benefits, access to expert guidance and skilled resources,
mentorship and networking connections, and much more.
Unlike others in the industry, Microsoft for Startups Founders Hub doesn't require startups to be
investor backed or third party validated to participate.
Founders Hub is truly open to all.
So what do you get if you join them?
You speed up your development with free access to GitHub and Microsoft Cloud computing resources
and the ability to unlock more credits over time.
To help your startup innovate, Founders Hub is partnering with innovative companies like OpenAI,
a global leader in AI research and development, to provide exclusive benefits and discounts.
Through Microsoft for Startups Founders Hub, becoming a founder is no longer about who you know.
You'll have access to their mentorship network, giving you a pool of hundreds of mentors across a range of disciplines
and areas like idea validation, fundraising, management and coaching, sales and marketing,
as well as specific technical stress points.
You'll be able to book a one-on-one meeting with the mentors, many of whom are former founders themselves.
Make your idea a reality today with the critical support you'll get from Founders Hub.
To join the program, just visit talkpython.fm/founders hub, all one word, no links in your show notes.
Thank you to Microsoft for supporting the show.
This one, I'm going to vote this next one here as probably the best icon of all the things we're going to talk about.
It's the Django Ninja.
Yes, they've done a good job with it.
There's a special flavor of marketing to open source projects, isn't there?
Yes, there is.
Yes, I think it's called none.
We could talk for hours on why it's called the GIMP.
Anyways, I find that because I'm a Django guy, I don't have a really strong need for single page applications.
A lot of the work I find I end up doing, Django templates is good enough for many of the pages in the application.
But then there's going to be some pages where you want to do fancier stuff.
So I often use view.js so that I can do best of both worlds there.
So I, you know, this is kind of a multi page application.
So those pages that require SPA kind of feel to it, they have view on it.
And those that don't, I just use generic 1.0 web style stuff.
So in the 2.0 world, you need REST APIs and enter Django Ninja.
This is what it does.
So it sits on top of a Django view and essentially RESTifies the view.
And I, when I say on top, I mean that literally you actually use decorators.
So you write a view, decorate it with an HTTP method like get or put, and then that view outputs JSON instead of your usual HTML.
The library is built on top of Pydantic.
So it relies heavily on the types to help it define the JSON that comes out.
You write a little schema file that says the names and types of the fields for the JSON output.
And it's got a schema that is based on top of Django models.
So this works a lot like a model form if you've ever used one of those.
So let's say I've got, you know, a Django model called a customer.
I can create a schema called customer out that inherits from Django, from Ninja's model schema.
I create a subclass called config, which is kind of like the meta subclass in Django.
And it sets the model attribute to point to the customer.
And if I want to use all the fields in the model, that's it.
It's basically just the three lines.
And you can customize that.
So like model form, you can say, don't use all the fields, only use these fields.
Or you can add fields if there's things like, say you want a field called name that combines first name and last name.
You can build something that computes that so that it doesn't actually use the model directly.
So oftentimes you end up having to write a couple of these because you often need the inbound and the outbound to have different fields in it.
So a common practice is to have your schema for customer be called, say, customer out or customer in.
There's nothing that enforces that, but that's how they do it in their documentation.
And I've kind of just sort of picked up the habit as you go along.
Yeah, it's so tempting sometimes to think, oh, we can just exchange the same model inbound and outbound in so many ways that just doesn't pan out.
Even if you're using something like Beanie or SQL model or something where like literally the Pydantic model goes in the database as well.
Often that's not even the same thing because, for example, your inbound create user, you want a password.
Your response, you'd never want to send the user the password directly back.
You shouldn't even know what it is.
The ID field is the most common thing, right?
Like every model's got one and there's hacks you can do to say, oh, if it's zero, it's a create, you know, and that's a common way of doing things.
But for Django Ninja, what I often just do is just leave it out.
And because there are objects like anything else, you can inherit it, right?
So you can start with the in and then add the ID to it.
So there's ways around it.
It's what it comes down to.
The Django Ninja can be plugged into an existing Django app.
It's not like a separate thing that I run that is also correct like Django.
It's actually just stuff that sits on top.
It's got its own routes.
So essentially you're building Django views, but you're decorating them with the Ninja.
And when you decorate it, it automatically collects all of those underneath one path in the URLs file.
So you set up a router.
Usually you set it to say something like slash API.
And so back to that customer example I was using, if I added a view for create customer, I set it to the customer path.
And because it's decorated, it automatically ends up under slash API slash customers.
So it takes care of a lot of that for you.
It looks like it also has async support as well, which is pretty neat.
It started from scratch with the asyncio.
I'm not 100% sure of this, but I think there's a couple former DRF guys on here.
And I think it was a rewrite from scratch with async from the beginning and Pydantic.
So I think it's sort of the next generation.
The key writers weren't in the DRF.
They obviously took a lot of learning from what was there and what worked and what didn't work.
It's pretty familiar to FastAPI type of programming.
And it has a lot of uses of type hints, right?
For example, you have an API function that takes a delay.
It says it's an integer.
I suppose it probably actually parses that and validates it and so on.
Yes.
And it's particularly useful as well because by the time you're getting things down, you
know, your web string, everything is string, right?
Like when you post it, it's all coming up in the string.
So somebody somewhere has to go, oh, that's supposed to be an int and try to convert it.
So it takes care of a lot of that kind of stuff.
And in fact, one of the reasons there's so little coding in this, particularly with the
schema definitions is because you're just, if you've already got that model file, it knows
the Django field is a text field or is a Boolean or is an integer.
And it goes, oh, okay, I know what to do with that, right?
So it essentially is building on top of that stuff that's already there for your existing
code.
That's really cool.
And you basically so much of the validation has already happened.
By the time it gets to you, you're much closer to the right answer.
You don't have to check so many things.
Much less code you have to write.
Yeah, for sure.
And if that's not good enough on top of all of this is it comes with a web-based debugging
view.
So it lists all of your registered calls.
You can go and click on things.
Authentication is required for the call.
And it's got a whole bunch of stuff in the back end for that as well.
You can click through and say, okay, I push this button and paste in my key or hit the
login button in my Django and then use it that way.
So it allows you to sort of see all of this and it includes in it the output in curl.
So as you're using the debugger, you can copy and paste the line into your terminal and then
run it in curl.
It's a quick little tool for helping you sort of figure it all out.
Pretty powerful.
It even has an interesting sync to async adapter decorator to allow you to work with the ORM
until it's kind of migrated along.
Shouldn't be as necessary now that 4.1's out because that was one of the major changes in
Django 4.1 is they added async to the ORM.
So yeah, that's really a big deal.
Yeah.
I actually remember one of the comments I saw on Twitter after 4.1 came out was, oh, the
Django guys, the ninja guys are going to love this.
I'm like, yeah.
Sounds like it.
All right.
Julio asks, is this as complete as Django REST framework?
And Nick Harvey says it looks lighter than Django REST framework.
Maybe give your thoughts and then we can maybe pull up the next topic.
Why don't we punt seeing as the next one is the Django REST framework and we can talk about
it as we go along.
The short answer is no, it's definitely not as complete.
So the Django REST framework or DRF to its friends is Ninja's granddaddy.
And it for a long time was the go-to REST library in Django.
Like Ninja, it breaks things down into serializers.
That's the equivalent of a schema and then views and routes.
And like Ninja, it supports decorators, but it also supports classes.
But because it's older, it doesn't support the type mechanism.
So you have to do a little more boilerplate code to get this going.
You have to do a few more things with the serializers.
It tends to, I was going to say it tends to favor a class-based approach.
I'm not sure if that's true.
When I write with the DRF, I tend to use the class-based approach.
There are other mechanisms in there, but it seems to be the one that felt natural for
me there.
It has a concept called a view set class.
And this is really where it shines because you define an object, which is an endpoint.
And then you can say inside of that endpoint, I want to do list and create and retrieve and
update and destroy.
And you tie that into your query set.
And it does all of those things for your object.
So back to my customer example, I could build out that customer endpoint.
And then I can say, I want to use list, create and retrieve.
And it'll allow me to create a customer or list all the customers or get a specific customer.
And it does it based on mix-ins.
So you can mix and match what, which of those choices you want.
So it's sort of this composing kind of mechanism.
I question or sort of an observation here from, to be fair, I haven't done much with
DRF.
But it feels to me like a lot of what you're getting with DRF is like, I have a database
table.
Let me do the rest things to it.
Like I want to be able to do a get against and get all of them or get against an ID and
get individual ones.
I want to be able to do a post and maybe create one where it's a lot.
It seems like it's very structured around CRUD, but over API.
Is that accurate or no?
There are ways around it.
So the concept of a serializer does not have to be tied to a model, but this is a tool for
Django.
So it's not really a surprise that it's kind of tied to the models.
And that's for the most part, even with Ninja, I find 80% of what you're doing over the rest
API is mapping to your database models in the first place.
particular if you're doing it for something like React, because the things in your database
are usually what you're showing up on the screen.
So it usually tends to map fairly easily.
And there's enough depth there that if you need to introduce new fields or do something
custom, it doesn't handcuff you.
It does allow you to do a lot of this stuff easier, though.
So like if you are sticking with things that map nicely to your database, then, you know,
it requires far less code is what it comes down to.
I guess to get back to that sort of question, it is just definitely lighter weight.
It definitely I find requires less code than the DRF because it takes advantage of things
like the typing that which DRF is older and it didn't exist.
And it was compatible with Python 2 and some of the stuff where those type pieces weren't
there.
DRF has a much richer output listing.
So if I were going to need something that was not JSON based, for example, over REST, I might
go back to the DRF.
So it's got mechanisms for either through it or through plugins, YAML, XML, MessagePack, Excel,
even LaTeX, right?
So there's libraries that go with these libraries that make this that sort of connect these things
together.
So, yeah, there's there's a lot of depth here.
The only place that the DRF makes me really, really nervous and is the permission mechanism.
I have shot myself in the foot a few too many times doing it.
It's fine by default, but then as soon as you start mucking with it a little bit, it seems
to open up a whole bunch of things.
You have to make sure once you start playing in that space that you do it correctly and test
properly.
Otherwise, you could have gaping holes.
Ninja seemed to be a little more locked down by default.
So I kind of liked that.
But that could just because I'm missing toes from playing with the DRF over the years.
You know what the guns look like?
Yeah.
Tishar asked, I think this is probably in reference to the Django Ninja.
It looks similar to FastAPI and how would you compare them?
It's a lot of sort of similar kind of concepts.
And in fact, you know, either between FastAPI, the typing mechanisms, is FastAPI directly based
on Pydantic or just deeply influenced by it?
I think just I feel like Pydantic became very popular because of FastAPI, but they're separate
projects.
Okay.
Separate maintainers.
Ninja is built on top of Pydantic.
So, you know, they're all being inspired by the same thing and trying to solve very similar
problems.
So it's not surprising me that people are seeing.
Yeah, exactly.
And at the bottom of the Django Ninja site, it says, this project was heavily inspired by
FastAPI.
Yeah.
My feeling is like, if you're already doing Django and you want to add APIs and you like
FastAPI, this might be a really good option because it brings so much of a similar model,
but you don't have to now maintain two apps that like run separately or version separately,
all that.
Yeah.
I also find it's got a little bit of a flask flavoring as well, right?
As to how some of those pieces.
And again, that's the same thing, FastAPI, using the decorators, using the types, right?
So it's a similar kind of influences if nothing else.
Yeah.
Very neat.
I think.
All right.
Django Grappelli.
What's this one for?
All right.
So a little bit of a tangent here for a second.
Django is named after a jazz guitarist named Django Reinhardt.
And he was often a duo working with somebody named Stefan Grappelli.
So if you're looking for a name for a library for Django, Grappelli is a good fit.
So now great.
We've got a name.
What does it do?
This is actually a reskinning of the Django admin.
So the Grappelli folks have taken advantage of the fact that the Django admin is built on
top of the Django templating mechanism, and they've rewritten all those templates using
a new style.
The style still feels a little dated, but not quite as dated as the Django admin.
So it's a step in the right direction.
It does logical things like a lot of the top right-hand corner, you know, reset password
view page.
A lot of that stuff gets moved into like little dropdowns and that kind of thing.
The coloring is a little more consistent.
It uses a footer.
So like the actions are always in the same place.
It just generally feels cleaner to me.
I often use the Django admin for like my backend support people.
Don't tend to use it customer facing.
So, you know, folks who are trainable and I find that when I've used it with them, Grappelli
feels better for them.
They just, it feels a little more intuitive.
So it's just a, it really is just a skin, but it's a nice skin and it's a really easy install.
You have very little you have to do.
You get a couple, a couple of changes to your settings.py file and it's all done for you.
So.
Yeah.
And also it looks like, you know, you hear skin, you think, oh, it's pretty, but it also
seems like it adds more functionality.
Like it adds autocomplete for foreign keys and relationships.
It adds like a tiny MCE, which is rich text editor.
It adds reordering through drag and drop.
I mean, those are a little bit more than just pretty, right?
It's modernization of the interface is really what it comes down to.
Yeah.
Very cool.
So another random Django bit of history to go along with the musicians was created in Lawrence,
Kansas, right?
Yes.
By the newspaper.
That's where I went to college.
So.
Ah, okay.
Right, right down the street from the home of Django around the same timeframe.
There you go.
Right.
All right.
So what's up next?
Import export.
So it's like a distributor.
It's going to make some money off selling rugs or what's the deal?
Rugs.
Yes.
Sure.
Rugs.
All right.
Unlike Grappelli, where you have no idea by the name, this one's a little better.
You might have an idea what it does, right?
Less creative, more straight to the point.
Like this is a utilitarian name.
I can import or I can export stuff from Django.
Okay.
That's exactly it.
How does it work though?
What?
Like, I mean, not just a database dump, probably something more interesting than that.
Yeah.
So it's built on top of Tablib, which is a Python library for tabular data formats.
And essentially it maps things out of your ORM to whatever Tablib can handle.
So that's Excel, JSON, YAML, Pandas, HTML, JIRA, TSV, ODS, CSV, DBF.
And I even know what some of those acronyms mean.
It's essentially your go-to place for spitting stuff out.
So like Ninja and like the DRF, it has this, what it calls resources.
This is like our schema.
And it essentially does that mapping thing again.
So you can say, I want to take this model and I want to map it to this mechanism.
And then it'll, you just run it and say, export this to JSON and you'll get it in JSON.
Export this to YAML and it'll export it to YAML.
There are mechanisms inside of the resources, similar to what I was talking about in Ninja
and the DRF to do compositing.
So if I want a name field, which is based on first name and last name, it'll combine all
those things and give that to you together.
One of the things that I like most, I haven't used this library a lot, but when I have used
it, it's because of this feature, which is it integrates nicely with the Django admin.
So you essentially can build one of these resources.
Let's say back to my customer example, let's say you want to be able to import customers.
You can essentially define the resource and then you add a mix in to your customer admin
object and it automatically gives you an import button on the client screen.
And when you hit that import, it'll upload, you give it the CSV file.
It gives you a little screen that says, oh, this is the data that's coming in.
And you can say, yes, I like it.
And it'll put it into the database.
And it's smart enough to know the difference between creates and updates.
So depending on whether or not your ID field is blank, this is back to that zero thing we
were talking about before.
It will actually update things that are there.
So if you've got a situation where you've got a client phone book or something that's maintained
through some other system and you need to keep them in sync, this is a quick and easy way
to do that.
throw it together with a management command and stick it in a cron job and you can constantly
push these things through.
It might sound really simple, but the ability to say, hey, business person or manager or salesperson,
you can just take your CSV and upload it.
You don't have to bother the dev team to add your data.
Like that's pretty fantastic, actually.
One of my clients is a very lightweight CMS.
And of course, when they sign up a new customer, they don't want to have to input their customer's
data by hand.
Right.
So you can say, oh, go.
You have it in an Excel file somewhere.
Great.
Save as put it in this format.
Suck it all the data in.
So it can make a big difference.
Yeah.
And the preview, make sure this looks good.
Like that's also an important part.
That's a lifesaver, right?
You know exactly what you're getting in there.
You can check it rather than it going, you know, running havoc all over your database.
Which it probably would if people just randomly start uploading stuff.
Exactly.
And that might make your app crash, but you could use the Django debug toolbar to figure out
what's going on.
Look at you, king of the segues.
Yes.
Oh, yeah.
So the next one here is, as you said, this is the Django debug toolbar.
So this is a plugin for Django that overlays over your views and gives you all sorts of
information what's going on in your page.
The installation is a little more involved than, hey, just add this to settings.py because
you need some middleware and some static files and things.
But once you've, the instructions are good though.
So as long as you follow the instructions closely, you'll be okay.
And once you got that going, it pops up in the top right-hand corner.
I think that's actually configurable.
And it has a list of panels.
It comes with, I think it's 12 of them.
And then there's a whole bunch of plugins that you can do as well.
So for example, there's history information.
A useful one I find I use a fair amount is the time panel.
So it shows you the breakdown of where, you know, where your call has been spent.
The one you've got up on the screen there right now is the one that saves my bacon all
the time, which is the SQL panel.
So it shows you exactly what queries were run, how long each of them took.
I understand enough database stuff to just get me in trouble, right?
The ORM provides this nice abstraction that I find really helpful, but I'm aware that I'm,
you know, sometimes I'm doing things that aren't efficient in SQL.
Or you don't know you're doing something inefficient, right?
You might not be aware you forgot a join.
Exactly.
And now you have this N plus one problem where you're like, I thought I did one query.
Why are there 50 queries, 51 queries on this page?
Exactly.
You know?
So when you've got that sluggishness, you go to the time panel, you see that you're
spending all your time in the SQL space.
Then you go to the SQL panel and you go, oh, okay.
So this is where it is.
I'm beating my database to death.
Why?
And then you can figure out, like you said, oh, I need to add an index or, you know, I
need to change the join or whatever.
Right.
So in the Django debug toolbar, it has a time section that says CPU and total.
And if the CPU time is the majority, then it's your Python code.
If it's not, then it's like, what are you waiting on?
Are you waiting on a database or an API?
Or go look somewhere else because it's not your code exactly.
It's an external resource that's holding it up, right?
Yeah.
So it helps you sort of pull these things through it.
And it's information that's available in any profiler as well, but it's there in combined
with other things.
So you don't have to go do it separately.
So there's other ones there.
Things like caching, headers, signal registering, logging, the list goes on.
And then it's a published mechanism for how you build your own panels.
So even on the main site, there's another 19 panels with instructions on how to write your
own.
And if you go digging, there are people that aren't in the official list as well.
So there are dozens and dozens of them out there.
For sure.
Probably in the awesome Django.
I bet.
You know, I bet there's like, there's a whole thing on the toolbar.
Yeah.
It was right there at the top where you're testing.
That's right.
Yeah.
I thought maybe there'd be a list of plugins as well.
Oh, a subset.
Yeah.
Like a subsection.
But yeah, these things are really nice and I find them to be quite useful on the, you
know, they've got different, I got the whole list here.
Like profiling.
That's kind of cool.
I guess one also, one really quick thing you might want to touch on for everybody is it might
not be best to put this in production.
Yes.
I think there's a rule against turning this off in production.
If I remember correctly, it will not run if debug is set to true.
It's to false.
Excuse me.
So by out of the box.
So if you're, if you're following best practices of setting debug to false in your production environments,
it won't be there.
It doesn't hurt to belt and suspenders that though.
I usually put this, if I'm using it, I usually put it inside of my, you know, requirements
dash dev.
And I have a little hack I use to build up my installed apps that I add to it from local
things, which there's a podcast in and of itself there as to how you configure in different
environments.
But I often only add this to that piece or hackishly commented in and out as I need to.
It's a little bit of a crude lever, but if it's not in the requirements.txt or pyproject.toml
or whatever, you're not going to accidentally run the toolbar if it's not installed.
So don't install it in production.
Yep.
Exactly.
Effective, right?
Yep.
How about some local flavor?
Yep.
Local flavor.
So this package eons ago used to actually be inside of Django and it just got kept getting
bigger and bigger.
And essentially this is the localization information for different countries.
So for example, the CA folder is for Canada, which is where I'm from.
It includes a list of all the provinces.
That's what we call states.
It's got a widget for postal codes, which is what we call zip codes and social insurance
numbers, which is what we call social insurance numbers.
Although we use a different acronym for whatever reason.
So essentially, if you're using things like shipping addresses, you want local flavor.
It's mostly just giant dictionaries and collections of tuples, but it's useful data that often you
would end up writing yourself.
And it's always nice when somebody else is maintaining it.
And for any fellow non-Americans listening, it is spelt without the U.
I'm not sure if it was intentional when they picked the name that the name itself needs
internationalization or whether that was just an amusing little accident, but that's what it is.
So even just having the country codes is great.
Is this something that maybe makes sense to use outside of Django or is it?
I'm not sure how easy.
I've never done it.
It might work.
It really is just a long dictionary and collections of tuples, but some of it's kind of Django
Django-esque.
For example, the list of provinces is set up so that you can use it easily inside of
a dropdown in a choices field.
Got it.
You might be able to take advantage of it without that, but it's formatted in a fashion that makes
sense in the Django world.
Good to know.
All right.
We already talked about the import and the export buttons, but even more buttons on the admin
if we want them.
Even more buttons.
Yes.
You can always do with more buttons.
So I've only used this one a couple times, but it saved me a whole bunch of work.
So I thought it deserved a mention.
The Django admin area pretty much is mapped to your model objects.
It really is just sitting on top of your ORM.
And every once in a while, you're going to need something that you want your support staff
to be able to do that isn't really directly tied to the ORM.
And in fact, I've seen libraries out there that hack things, creating fake objects inside
of the database so that they will show up in the ORM properly.
And instead of doing that, you use admin extra buttons.
So this is really just a way of inserting views into your admin.
And it's got a quick little mechanism for forms so that if you hit a button, it'll pop up the
form for you.
You can fill in the form and then it'll give you the data from the form as a callback.
And then you can do whatever you want with it.
So where I've used it recently was I had a complex count creation mechanism that has to create
like five or six different objects that have to be tied together.
So instead of having my support staff going in and using the admin to create each one of
those separately, I gave them a little button.
They fill in the form and it creates all the objects and ties them together nicely.
And actually just a couple of days ago, I added one, which was sometimes I'll have in
production code, like a couple of accounts that are like sample accounts that you want
to reset the data to a known state so that you can hand it off to demo somebody or quick
if you're trying to sell a client or something.
So this doesn't even require the form.
There's a mechanism in here called confirm action, which essentially is it gives you the
button.
It pops up a little thing that says, are you sure you want to do this?
And if you say yes, it goes off and calls your little five lines of code.
So it's nice and clean.
The form rendering is ugly is the word, but that kind of fits with the traditional,
traditional.
It's traditional.
It fits very nicely with what's inside of the Django admin.
It doesn't look out of place, but there's nothing sexy with it.
I have not used it in combination with Grappelli yet.
So it'd be interesting to see what happens in that case.
There's basically very little styling on the form, but it has saved me a whole bunch of
code.
And oftentimes I find when you're writing things for your support staff, they're spending 90%
of the time inside of the admin anyways.
So pulling them out of it for one special page is a bit of a pain.
And you usually have to write a whole bunch of extra stuff on top of it.
And so this, because it inserts it right inside of the admin means you don't have to get them
into a different place.
And they're in an interface that they know how to use and makes things easier.
So very much like that import export.
If import export didn't exist and give you that button up top, this would be a way of building
it.
Really nice.
And it's very decorator heavy.
It is.
Yes.
Yeah.
Everything's a button or a view.
And you've got up on the screen there, right?
That's the confirm that I was talking about at the top.
You call it decorate the view.
And that's because in this case, you're inserting it inside of the actual Django admin model pieces,
right?
So you have to essentially, the decorators are doing the registration to say, okay, this is
extra code for the admin.
It's how they're hooking it all.
Yeah, it looks very, very useful.
All right.
We've got a couple more.
Yep.
This one, I think I know the guy who created this one.
Yes.
So this is a little bit of blatant self-promotion.
This is Django All, A-W-L, like the leather working tool.
And yeah, this is one of mine.
If I had been aware of the Django extensions library at the time that I wrote this, I probably
should have just contributed to the Django extensions library.
It would have been the smarter thing.
But at the time, I wasn't familiar with it.
And since then, I've been maintaining this beast.
It's a general collection of a whole bunch of crap, like extensions that I just found
I was writing over and over again every single time I went to a client.
So one of the times I was doing that, the client, I went to the client and said, let's open source
this stuff.
And they went, okay, great.
And since then, I've been doing this.
You sell widgets.
You don't sell Django admin extensions.
Like, let's make the world a better place and contribute back ideas.
Exactly.
This will hurt you.
Big list of random crap, right?
So a bunch of mix-ins, CSS color utilities, some context processor pieces.
Custom admin commands.
Yep.
There's decorators in here that make sure that you're doing a post with JSON content.
So that if somebody's calling your view in the illegal way, it screams ranked models.
So one, two, three, four, five, and gives you a little thing inside of the admin to move
them up and down.
Some testing tools.
So there's a custom test runner in here, which adds a whole bunch of features for doing
things like getting out information out of the Django admin and checking that the fields
and the admin are correct.
So really just sort of a little catch-all that's out there.
But yeah, it's here and I happily take PRs.
So go find it, break it.
If you find it useful, great.
If you don't, send me a note and tell me why not and I'll fix it.
Yeah.
Lovely.
It looks really useful.
I'll stop with the shameless promotion after this one.
Hey, I'll keep going.
These are good.
This is a Django airplane.
So I used to, I used to have to do a lot of traveling when I was consulting and being on
a plane is a great place to get some uninterrupted four or five hours of coding in unless you're
coding on the web.
And particularly in the olden days when you didn't get wifi on the planes and even now it's
spotty and expensive.
You can't really count on it.
Yeah.
So what I found was, you know, if I'm using something like bootstrap from a CDN, I would
get in and I'd be trying to run my Django site and be like, oh crap, nothing's looking right
because the CDN is there.
So this is essentially a little tag that you use anywhere where you would use an HREF for,
you know, links or style sheets or whatever.
And then there is a setting that defines the mode of the system.
And if you're in build mode, anytime these tags find it, they'll go off, they'll grab the
content and they'll save it to the disc and just runs the page normally.
And then when you're in cache mode, instead of trying to get to the internet, it pulls it
off of the disc.
So it's nothing terribly complicated, but it solved a particular problem that I was having
a lot.
And now that I'm not really traveling, I'm not touching it as much, but if folks out there
find it useful.
People travel less.
I don't know.
It's kind of weird.
Yeah.
There's been a few changes.
Life has changed.
There have been changes.
Although I did travel recently in a pandemonium.
So if you want madness, you can go back and try to fly.
Yeah.
So this is really nice.
So basically you say airplane, instead of a static ref to a CDN, you say airplane and then
the reference to the CDN and either it just passes through or it can download and then
pass through, or you can say I'm in this development mode.
Just, I don't have, I'm either at like a coffee shop or I'm traveling or whatever.
And just let me, I'm, you know, another good use case, not just airplane, even though that's
the name is if you're at a hotel with notoriously bad internet and you're traveling for work and
you got to get a presentation or new version ready for the morning, like that can be a super
frustrating experience.
It essentially moves anything that's normally on your internet down to your hard drive.
If you've tagged it properly and there's a couple of management commands as well.
So like, it'll tell you what's in your cache and you know, how to see it and how to wipe
it out if you need to.
So there's a couple little utilities, but like I said, it's one of those, one of those libraries
that is simple, doesn't do a lot, but solves a particular problem.
So if you're having that problem, go for it.
Yeah.
Fantastic.
Your example is for a CSS.
Can I like leverage this to like JSON API somehow like offline, some API calls or anything,
or is it, is there not really a way to fit that together?
I don't think it would work.
If it's a straight URL that was always coming back with the same value and it was hard coded,
it probably shouldn't care.
But yeah, it would depend on how you were using it.
Yeah, sure.
Last one.
The thing you always put last security, right?
Just kidding.
Okay.
We're skipping ahead.
Got it.
No problem.
Oh, are we skipping ahead?
I had a Django extensions next.
So.
Oh yeah.
I think I just didn't open that one.
That's fine.
I kind of touched on this one when I was talking about Django All.
This is a collection of things that probably should just be built into Django is really what
it comes down to.
There's a whole bunch of different areas.
Again, it's this huge hodgepodge.
So there's extra tools for the admin, more management commands, more signals, template filters, extra model fields, job management.
It's a very lightweight job management.
But if you're not at the level where you want to use Celery or something like that, this might be good enough for you.
Some model mix-ins, permission mix-ins, extra validators, some utility methods.
The one I use here all the time, particularly when I was learning Django Ninja and I was trying to understand how the router worked, is a management command called show URLs.
It'll show you all the URLs you've registered, what their keywords are, and how to call them.
So it's a nice little introspective kind of thing to work through backwards.
It's got another management command called run script.
And this one's so useful that I had the exact same thing in Django All.
Again, as I said, I should have just looked at this library first.
And the idea of run script is it gives you a Django context for running a Python script.
So this is kind of like the dash dot slash management shell command, where it gives you inside of a Django context, but it does it for the script that you're running.
Oh, that's cool.
So things like the database are initialized and stuff?
Exactly.
Yeah.
Okay.
I find I generally use it if I'm debugging, right?
So if I've got three or four things I want to do in the database and I need to run it three or four times until I figured out what the problem is, rather than constantly doing that in the REPL over and over again,
you stick it in a file, run the script, look at your debug or use it in the debugger.
Of course, is the other thing there, because you can step through that a lot easier than you can say inside of a inside of a REPL.
So a lot of good stuff here.
And it's one of those libraries that I find every time I look at it.
I'm like, oh, I have to remember that's there.
And then I forget.
But you always have to sort of go back and dig through it.
So it's a good little toolbox.
Diff looks cool for probably pre-post migration.
There's three or four SQL commands in there that'll tell you how your migrations are, how they've changed, how you're managing them, what it's doing to them.
Django has since added a couple things that are similar to it inside of the core library.
But these are definitely more powerful.
So, yeah, if you're trying to figure out what's going on with your models, there's some interesting stuff in there as well.
Yeah, fantastic.
All right.
Maybe that brings us to Django All-Off.
This is it.
This is the last one.
So this is Django All-Off.
This is your go-to place for authentication.
It has a series of workflows in it that are your typical user management things like sign up, email addresses, email verification, password resets.
And so I don't usually use it for that.
I use it for the thing that most people use it for, which is it's got this hook for your social media account authentication.
So most social media sites use either OAuth or OAuth2.
And so if you've ever been on one of those web pages that says, you know, you can sign in or create an account with your Facebook account or your Google account, this is a plugin that allows you to do that inside of your Django space.
They have over a hundred different providers.
I stopped counting.
I just gave up after a while.
Most of them are overlays on top of OAuth2, but there are also some that are custom as well.
And what happens is when a user signs up using one of these, it still uses the standard Django user, but then it creates an associated object.
And the advantage of this design is it means different users can use different things.
I can sign in using Facebook.
You can sign in using Git or Google or GitHub or Google.
But we still end up in the same user style account inside of the database.
But the other advantage of it is you can also associate multiple things.
So say you were writing a site that wanted people to be able to log in through GitHub or GitLab, but also wanted to be able to tweet.
Well, you could not necessarily allow logging in with Twitter, but you could allow them to authenticate through it so that you could tweet on their behalf.
So it allows you to start connecting and play with all those things.
The plugin, the workflow is plugin.
Try that again.
The workflow is pluggable as well.
So there's hooks inside of the signup process.
So let's say you've got some questions that you need to ask the user when they sign up, like extra information that Django doesn't normally have.
It's got a flow for that that helps you with it.
So really, really comprehensive library.
The only thing I find that's challenging with this really has nothing to do with the library itself.
It's just that third-party authentication tends to be messy.
You are always dealing with tokens and provider sites and all the rest of it.
And you're going to be...
Have you registered your OAuth application at...
Exactly.
...AngelList?
Did you do it right?
Like, oh.
You're always going to be in this space of, did I screw it up?
Is it the token that's not right?
Am I not hooking the library incorrectly?
I always find it's a little finicky.
Now, once you get it going, it's fine.
But there, it does tend to be a little cumbersome getting there.
Yeah, it's a little magical in, like, the traditional sense.
Like, it can just work amazingly.
But if it doesn't, you're like, I just don't know what the incantation I'm supposed to give it is.
Because it's just not...
It won't.
It won't do the thing.
You're debugging something that is somebody else's responsibility.
So you're not getting a lot of information out of the host system, usually.
Yeah, and often it's encrypted and signed and, like, stuff doesn't match.
It's like, how are you supposed to know how it doesn't match?
Anyway, but, I mean, that's the story of OAuth.
OAuth 2, not this library's problem, right?
The library makes it a lot easier.
It's just, like you said, there's still a level that is painful.
It swims in complex water.
One thing that is kind of nice here is you can unroll your OAuth as well.
You can say, I did originally sign up on GitHub, but I just want to make a password from my account now.
I'll let you drop that out, which is, I think, kind of cool.
I think it was a very smart architectural decision to continue to use the Django authentication mechanism underneath.
It means, from a support standpoint, you don't have to worry about a lot of things.
You can still see them inside of the admin.
You're not having to worry those pieces.
And like you said, if something goes wrong with somebody's Facebook account, you don't lose anything.
You basically, you know, they can send you a support email and you can send them a password reset off of a primary account and rehook them up another way, which is a thing of beauty.
Yeah, that's great.
All right.
Well, I would say we're a little over time, but it's been a super interesting list to talk through with.
So maybe call it a wrap on however many topics we came up with.
A whole bunch of cool ideas for doing more with Django and Python web apps in general.
So thanks for that.
Happy to do it.
Yeah.
Now, before we get out of here, I've got to answer the two questions.
Well, I've answered one of them already.
You're going to write a code.
What editor do you use?
Yeah.
So I'm Vim.
And for those who are taking the course, I used PyCharm there.
So you don't have to understand antiquated.
Speaking of magic, you don't have to follow along there.
So I did use PyCharm there, but Vim is still my standard.
And then notable PyPI package.
It can be any one of these you want to give a shout out to.
We've really kind of answered that question a bunch of times.
But if you want to give a shout out to something else as well.
I got something else for you, which is Ascii Maddox.
So I do a lot of TUI work and I'm really keen on this library.
They have a bunch of form widget stuff and also a whole bunch of cool, awesome 80s style
animation bits and pieces.
Core developer is a guy named Peter Britton.
Very responsive.
Always looking for MRs.
So yay, Peter and Ascii Maddox.
So if you're into this space, this is definitely something to check out.
Wow.
Amazing.
Yeah, it looks pretty awesome.
All right.
Great example.
All right.
Final Call to Action, so many of the things that we've talked about here, if they're
interesting, people want to learn how to actually use them.
Grappelli, create your own admin command, a bunch of other stuff covered in your course.
So check that out over at talkpython.fm.
Just click on courses, find the Getting Started with Django course.
Well done on that.
Thank you so much for coming here and sharing all these.
You know, maybe give a final call to action.
People want to get started with these ideas and bring some of the material to their apps.
What would you say?
I think a lot of it depends.
You know, anytime I'm trying to learn something new for me, it's always about the project,
right?
So if I, you know, if you're doing something that needs the REST API, then, you know, Ninja
or DRF might be the place to go.
If you're, you know, if you just want to play a little bit, then, or you're learning more
about how Django works, the debug toolbar is a fantastic way of sort of learning some of
the internals and taking your Django to the next level, because it's exposing a bunch of
that stuff that you kind of think you know how it works.
Yeah.
It's a nice little place of doing a tutorial.
So those might be good places to start.
Yeah.
That's cool.
The framework tries to hide a lot of that stuff.
The toolbar will like reveal it what's going on, right?
Yeah.
Well, as good framework should, but every once in a while, you want to see the guy behind
the curtain.
So that's right.
All right, Chris.
Well, thank you so much for being here.
It's been a whole lot of fun.
Enjoyed it.
Yeah.
Same.
See ya.
Cheers.
This has been another episode of Talk Python to Me.
Thank you to our sponsors.
Be sure to check out what they're offering.
It really helps support the show.
You care about the ideas behind technology, not just the tech itself.
And you know that tech has an enormous influence on society.
So check out the IRL podcast.
It's hosted by Bridget Todd.
And this season of IRL looks at AI in real life.
Listen to an episode at talkpython.fm/IRL.
Starting a business is hard.
Microsoft for startups, Founders Hub provides all founders at any stage with free resources
and connections to solve startup challenges.
Apply for free today at talkpython.fm/founders hub.
Want to level up your Python?
We have one of the largest catalogs of Python video courses over at Talk Python.
Our content ranges from true beginners to deeply advanced topics like memory and async.
And best of all, there's not a subscription in sight.
Check it out for yourself at training.talkpython.fm.
Be sure to subscribe to the show.
Open your favorite podcast app and search for Python.
We should be right at the top.
You can also find the iTunes feed at /itunes, the Google Play feed at /play,
and the direct RSS feed at /rss on talkpython.fm.
We're live streaming most of our recordings these days.
If you want to be part of the show and have your comments featured on the air,
be sure to subscribe to our YouTube channel at talkpython.fm/youtube.
This is your host, Michael Kennedy.
Thanks so much for listening.
I really appreciate it.
Now get out there and write some Python code.
I'll see you next time.