Why Is the Django Admin "Ugly"?
coderedcorp.com
coderedcorp.com
It was definitely not intended to be ugly — the first version was designed by Wilson Miner, a great designer. In fact, an argument could be made that a key reason for Django's early success was that the admin was so nicely designed. Same goes for the framework's website in general; the standard open-source project website in that era was really plain and uninspiring.
To answer "Why is the Django admin ugly?", I think there are two separate issues:
* A gradual bolting on of admin features without enough thought given to visual consistency and elegance. Particularly, the left sidebar (in the screenshot of the original article) was a later addition and looks unpolished.
* A misunderstanding of the Django admin's goals. It's meant to be for "internal use" — that is, it's meant to be used by people who operate your website, not by people who visit your website. Ever since we open-sourced Django, many people (through either laziness or lack of understanding) misunderstood the point of the Django admin, thinking it's meant to be for end users. It is not and never was.
I can understand the admin isn’t meant to have a "consumer" UI but it still feels like there are lots of user experience & accessibility improvements needed to bring it in line with modern standards (WCAG for example).
And it isn't! I started using Django in the days when it was in perpetual Beta - back in 2008. It was not ugly by the standards of those days.
After over a decade's hiatus, I'm back to using Django for paid work. And I still find it "not ugly". Sure, it doesn't have bells and whistles, but it's pretty functional, and doesn't offend my aesthetics at all!
PS. I owe a lot to you, Jacob and Simon - thanks for Django! My funding in grad school was drying up, and I needed a side job out of my department to help pay bills. And fortunately, one team at the university was looking for a Django programmer. I was not a CS major, but knew enough programming to get that job.
This just confuses me. It's called "admin" for a reason...
I found one great middle step is a `simple_form.html` template and using Django Forms to quickly and easy generate a lot of CRUD views. You can also use a `simple_delete.html` confirmation template to handle that. These templates can be used on any number of pages.
Then, as your app matures, you can add more custom templates and maybe eventually switch to Django Rest Framework and an SPA, if it fits.
We now have a new generation of developers who learned on fancy JS frameworks, SaaS dashboards, A.I.-enabled tools, etc. These new devs learning Django now in 2023 have never seen anything like the Django admin.
So with this article I'm just trying to pass on the tribal knowledge as to when to use it, and why it is what it is.
I use Django exclusively for all my product work and it's... amazing...
... and I was recently consulting on a project where we had to make extensive additions to the Admin views and it was amazingly versatile, flexible, and pleasantly surprising in supporting everything we needed.
Is a cast iron skillet beautiful? Probably not, yet it has stood the test of time and people swear by it. I feel the same way about Django Admin. :)
I'm soooooo sick of React doing completely hostile things like flashing incorrect information for empty widgets or completely breaking page location when hitting the back button.
Seems like every few years it becomes accepted to make the web worse for users because of front end fashions.
This isn't really React's fault. Avoiding the things you mention is entirely possible when using React. It's all up to the developer to handle such scenarios, just as it was without React.
You can choose to have higher latency for the initial request and just display static HTML. Or if you want to load content on demand, then you do have to deal with what happens before anything loads, but I don't think that's the fault of React. Any framework which does this is going to have the same problem that needs to be solved.
Similarly to React "breaking" the back button. If you want user interaction without another page load, you have to deal with the consequences such as needing to track page history more explicitly than you might have otherwise. But that's because the dev chose to change the page content without moving to a new URL, not because that was implemented using React.
It's not possible to flash misinformation with normal front ends before React, without going to extreme extra effort to enable such misbehavior. Whereas with React, the easiest programming path is the user hostile path. And React is adopted only to make it "easier" on programmers.
Nothing about React specifically enables that kind of design.
Redux encourages loading data like that, and the easy way to use Router makes it easy to do that - all URLs get sent to the same backend view to render the app, then the frontend takes the URL args and triggers ajax to get the data. During that interim when the ajax is running is when you get this empty-data state.
For every consequent page transition the performance is actually slightly higher than a full page load since (a) you're probably only fetching JSON instead the entire resulting rendered HTML and (b) you don't have to load the app code any more.
jQuery, Backbone, Angular, etc.. You can / did do this in other frameworks prior to React.
I think, from reading your comments, you think client side routing and single page applications equals React. That's... an interesting take.
If my irrational hatred has a better target than the term "React" I would like to know it. I do despise the usability of nearly every SPA I have used. It is perhaps possible to program an SPA so that the deficiencies are not noticed, which is great, but that does not appear to be the norm nor is it made easy by SPA frameworks.
The flash of inconsistency you see is because the client eagerly modifies state before the server persists it (or some form of this problem).
The routing issue is because the application (SPA) is using business logic to control the browser's navigation state. Sometimes opening a modal will be a new push on to the nav stack so you can hit back, sometimes it isn't, sometimes they forget things, etc..
All of it though is just too much state being managed on the client by the application and that state being managed poorly. This isn't only related to React. It's always been possible to screw up with managing state in any framework.
Mission accomplished?
Either way, it's a lot of text that shows up in a consistently stylized and clean way, which is tough to achieve for something like an admin panel.
It's purely visual though. It's a great piece of software to get out of the box.
All joking aside, I like that the Django admin still looks the same after almost 20 years. Cannot begin to impart how much value that thing has provided me.
An aesthetically pleasing interface is a side effect of someone fluent in that language working hard to figure out how to communicate information, action, cause and effect, etc to the end user. It's not an easy language to learn, it's important even in relatively trivial cases, and developers trying to wing it are about as good at it as designers cargo-cult assembling PHP to modify a WordPress deployment: It might get the job done in a very basic way, but nobody should convince themselves it's a real solution. Just like a developer might look at their interface and say "read the docs" or "design is subjective," that designer might see how slow their 5-deep for looped set of database queries is and say "this server is too slow" or "why can't those damned developers make WordPress faster?"
I agree with what you say somewhat, but I believe about the massive difference between UI/UX. If I have to sign up to something for the first time or have to buy something, I want pretty pictures. If I have to work with something often (all day let's say), I want UX and I couldn't give a shite about UI; I want things easy to find, fast (not latency) etc. Combined would be great, but tell me what has that, because I always see one, never both done to perfection. If there is a 50/50 mix, it's usually annoying as hell on both sides.
My most productive interfaces are ugly as hell ; no animations, no overhead and everything crammed on a screen and very fast. I would never 'sign up' for an application like that seeing it first, but I would never use any application long term for productivity like most people say is 'beautiful' because it's inefficient.
Are they settings that Meta wants you to change?
There's bo difference. The GUIs have started rapidly going downhill right after some idiots decided they are different and the rest of idiots believed it to be true.
How can you have a UI without understanding how it functions and how it's used?
A/B testing isn't immune to being as broken as the UX in some of the gnarlier bits too. Perhaps some of the links that simply don't work on the Facebook mobile app are busy signalling that they get way more clicks than the one that successfully loaded the content...
Google's terrible at UX. I once spent about five full minutes figuring out how to navigate my dad's phone app on his Android phone, so I could help him use it, after an OS upgrade. There were some tabs that didn't look like tabs and didn't indicate which was active, turns out. He'd have had no hope of figuring it out on his own.
Once was helping my grandma add contacts in Gmail. She had failed repeatedly. Kept hitting "add contact" and it'd blank the form she was on, without adding the contact. This was because there were two same-color-and-weight add-contact buttons on the page, with the same copy, and one submitted the form, while the other gave you a blank contact form. You pretty much had to be familiar with how HTML nesting worked to have good shot at guessing which was the one you wanted, just by looking at it.
That second one's an older version of the UI, but holy shit it was bad. They definitely make mistakes, and really obvious ones at that. Money and "smart" doesn't mean shit.
Really though? Does your web browser interface look the same as your sms/messaging interface, look the same as your car's annoying infotainment interface, look the same as your mail client, look the same as this website, look the same as your search engine? Do all of those things really look the same as they did 10 years ago? We use so many interfaces that are subtly shifting and being improved that the ones that work well for right now don't even stick out to us, and that's part of the problem. If you don't really notice that you're using an interface and are entirely focused on solving the problem you need to solve with that tool, then that's probably a really well designed interface. It's probably so smooth and intuitive that it seems like designing it that way would be obvious, but it's really, really not.
> If I have to work with something often (all day let's say), I want UX and I couldn't give a shite about UI; I want things easy to find, fast (not latency) etc. Combined would be great, but tell me what has that, because I always see one, never both done to perfection. If there is a 50/50 mix, it's usually annoying as hell on both sides.
You don't have an particularly accurate understanding of these roles. If a UI doesn't let advanced users solve their problems efficiently, then it's a shitty UI. "Pretty Pictures" where not appropriate is bad UI design no matter how pretty it is and people who don't think so are visual designers (at best) trying (and failing) to be UI designers. A well designed UI is an effective UI. All of those pretty UI mockups you see on sites like Dirbbbbbbble and behance are nothing more than aesthetic explorations. There's no way you could even know if they were good or bad UIs because you don't know exactly what problems they were trying to solve, for whom, and in what context.
UX encompasses the entire experience. If you have a great UI but the world's shittiest email confirmation workflow, then you have a UX problem with a great UI. This misconception is why developers think adding the ability to select color themes in their application with a horrible UI will address UX problems-- which to any actual software designer is complete nonsense.
> My most productive interfaces are ugly as hell[...]
A couple I'm friends with had a broken kitchen faucet handle for ages-- it would just fall off unless you held it on while operating the faucet. Unfortunately, one of the necessary connector pieces was no longer available, so it wasn't a trivial fix. Once, when I was pet sitting their rabbits, I got so annoyed by the thing that I went home and made a wooden piece to fit in where the missing part went, and fixed it while they were still on vacation. It was supposed to be a surprise but I totally forgot about it, and a few months later my wife said to them "hey do you like having your kitchen faucet fixed?" They looked at her, perplexed, walked over to the kitchen faucet, tried to pull it off, and it obviously didn't come off. They were shocked! Why? Because they were so used to holding that damned handle on the faucet that it just became an part of their using that faucet.
So not to be flip, but, the sky is blue, water is wet, and technical people are tolerant of and used to using shitty interfaces. Open source user interfaces are almost exclusively used by technical people; there are a few exceptions like Firefox, but Firefox's interface is managed by a team of foundation-funded full-time professional designers, (actually they do a lot of really great open usability work.) One exception I can think of is Inkscape. Most open source interfaces are absolutely awful. Why were they designed that way? They weren't. In fact, they weren't designed at all. They were assembled, ad hoc, to expose functionality in a way that made sense to whoever was creating the functionality. Those interfaces, more often than not, are more representative of their implementation than the problem they're solving, and unless you have a working mental model of how software works, and often specifically how that exact process works, the interfaces are practically useless.
There's a big difference between harder-to-learn-but-amazing interfaces-- vim, emacs, oboe, airbrush, airplane, etc. -- and interfaces that are entirely unedited. People are always going to be most productive using interfaces that they're used to, and that often mistakenly leads them to believe that what they're used to is objectively good. If you ask nearly any group of professional photographers how many hate Adobe, most will raise their hands. Ask them how many have used Gimp, they'll almost all raise their hand. If you ask them how many used Gimp more than once, they'll almost all lower them. Ask them why, and they will almost guaranteed cite the poor interface. While many dedicated and experienced FOSS developers (which I am) will cite Adobe's marketing practices as the reason people use Photoshop instead of Gimp, I call bullshit. You'll find many more photographers using Affinity Photo than Gimp, and considering Gimp is free, that says a lot. Who will you find using Gimp? Developers that need a photo editor. Why? They're so used to holding on the faucet that they don't even recognize when they see a properly working one. (And they'll often get really mad for even implying it needs to be fixed.) You also don't see that split with Inkscape. Most people who professionally work with vector art choose Illustrator as their primary tool, but most of them cite exactly the reasons developers assume people continue to use photoshop: overall smoothness, ecosystem integration, file type compatibility, etc. There are some legitimate shortcomings in Inkscape-- the type tools are just not as good which matters for graphic designers, for example. But lots of people who do vector art professionally do use inkscape.
Regarding Instagram et al, before you question whether or not the interface designer did a good job communicating, you need to know what they were supposed to be communicating. I'll bet they did a fantastic job at surfacing what what marketing people thought was useful for marketing, sucking in people's attention, and funneling them into profitable paths. The problem isn't that they're bad at it— the problem is that they're good at it while working for an organization that has shit motives. Similarly, the developers that make Instagram are still very very good developers even if a lot of their energies go into making super shady privacy-smashing telemetry. The problem isn't developers or software development, it's the goals handed to those developers.
My perspective is that we have a new generation of Django devs among us, who grew up using fancy JS frameworks, SaaS dashboards, A.I.-assisted code tools, etc. So for a newcomer seeing the Django admin for the first time, it's a bit different.
My goal of the article was to capture the tribal knowledge that seems to have not gotten passed down to this new generation.
You don’t just submit a pull request called “Redesign”. The with is more political and organizational in nature
Not sure if English is your native language, but quotation marks usually land on the outside of any other punctuation. (Yes, it does look goofy.)
Now, the quote above is kind of special because you have a portion of it quoted within a statement. However, if you are paraphrasing all but the "ugly" part. In that case, I would drop the outer quotations marks.
> why is the Django admin so "ugly?"
Bring on the downvotes.
Question marks are a little different. If the question mark is part of the quote, place it inside the quotation marks. If the question mark is not part of the quote, and instead the quote is part of a question, place it outside of the quotation marks. This rule also applies to exclamation points.
- https://www.grammarly.com/blog/quotation-marks/
Place a question mark or exclamation point within closing quotation marks if the punctuation applies to the quotation itself. Place the punctuation outside the closing quotation marks if the punctuation applies to the whole sentence.
- https://owl.purdue.edu/owl/general_writing/punctuation/quota...
Different varieties and styles of English have different conventions regarding whether terminal punctuation should be written inside or outside the quotation marks. North American printing usually puts full stops and commas (but not colons, semicolons, exclamation or question marks) inside the closing quotation mark, whether it is part of the original quoted material or not.[14][15] Styles elsewhere vary widely and have different rationales for placing it inside or outside, often a matter of house style.
On extending the admin – perhaps there’s something to be said about the admin coming with more UI components built-in? For example it lacks any dialog / modal window implementation, or an "accordion" / disclosure pattern. Or things like support for keyboard shortcuts.
> The admin’s recommended use is limited to an organization’s internal management tool. It’s not intended for building your entire front end around.
Cue someone used to working in “scale until you die” startups telling me that any time not spend on juicing MAU is time wasted. I like working in sustainable businesses.
I’ve worked with Django for a decade. I’ve done ungodly things with Django admin. Things most people wouldn’t dream of. I am completely over doing any of that. This isn’t a fault of Django admin. It’s very good at doing what it’s intended to do. It’s just a very common beginner’s trap to try to push it further than it wants to go.
There’s plenty to critique Django admin for. I fought with it just last week. At the same time, most complaints I see about it tend to be people (IMO) misusing it. It’s the service panel. And yes, people other than the engineers that built the thing have reason to pop open the service panel. These are your mechanics. But, and especially for SaaS products, don’t conflate “user” with “customer”, and not think about your other audiences.
I think there is Trader UI, and VC UI. Trader UI, built for wall st packs every bit of information into every pixel possible. VC UI has rounded corners, nice fonts, drop shadows and half the information on the screen. Django UI actually splits the difference nicely.
A more charitable way of putting it is, you can make a pretty presentation when you know the data that you are trying to present and the story you are trying to tell. I can't imagine a 3 column pricing table that wasn't done in bootstrap (Venture Capital UI)
Traders look at screens searching for meaning across a bunch of different data. They are trying to construct a story and as much context as possible is important.
The problem comes when VC UI is applied to a Trader problem where you want to see as much information as possible to understand, but there is padding, rounded corners and other stuff forcing you to scroll.
Look at this screenshot of a Bloomberg terminal
https://www.investopedia.com/thmb/trBFMDD8xeZkhLiLscngql3FV_...
It being ugly is a feature. Don't fall for the temptation of giving non-devs access!
(But it could have kept it's look while still being more friendly to use, though. So many huge selects and difficulties to fill in valid data in some cases)
I think an OS-managed popup window is superior to a page-managed modal since it allows you to move the window out of the way or even switch away from it, where as a page-managed modal is generally fixed in place, blanks out the parent page, and the only way to get back that parent page would be to dismiss the modal which discards your input.
I'm also not sure whether the accessibility concerns are substantiated - surely window management would be a well-trodden path for any screen-reader user and whatever you build yourself in-browser would have different and unexpected semantics that would require the user to get used to it.
[1]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/di...
The HTML <dialog> element is used to create both modal and non-modal dialog boxes. Modal dialog boxes interrupt interaction with the rest of the page being inert, while non-modal dialog boxes allow interaction with the rest of the page.
The modal dialogs are easier for the programmer to use but they're quite inconvenient because generally, they ask you a question you can answer only by looking at/interacting with the rest of the page. Which you can't do (the modal dialogs on web also almost never can be dragged around).The devil is the details for real world usage on your data and it's relationships.
The simplicity also makes extension simple. I could add a few features.
Django Ninja is a breath of fresh air.
Is it the shiniest UI? No, but a well configured Django admin is a power tool that stays out of your way.
It's not uncommon when starting a new project that I pick Django just to have Admin, and then ignore its usual views altogether.
When clients ask me re-design it, I will deny it.
I did the re-design of admin panel once, and what we produced was better in design yes, pretty even, but not usable, people got lost in it thinking it's still the main site and not admin panel, and there were only 3 admins, 2 of which were management.
In my opinion, it's good as it is.
One of the eye openers for me personally was the realization that the Mastodon organization contracted a UX engineer firm. It shows.
Grappelli was OK for a short time, but even it's too dated to use now.
The number of "What if I used Bootstrap made everything look like a horrible Bootstrap site?" packages is hilarious.
If yes, it's probably better than 95% of other admins.
Very easy to get started though, and even comes with stuff like cron jobs and email sending triggers built in and able to use in super simple manner https://pocketbase.io/docs/js-jobs-scheduling/
according to his benchmark you can serve 10,000 realtime connections on a 4 dollar a month server https://pocketbase.io/faq.
my basic deployment was just rsyncing my pocketbase folder into my vps and creating a systemd service. i'm now adding some github actions and docker files but it might not be necessary https://www.programonaut.com/pocketbase-as-a-framework-deplo...
Only one rounded button?
If you want an admin wrapper around your database, you have better many modern alternatives (I use directus). If you want low code and easy platform, you have bubble.io. If you want an easy api for your database, you can use things like hasura. If you want python frameworks, try fastapi (its third party admin is great). If you want an orm, sqlalchemy gives you more bang for your buck.
Many of Django's third party packages are out of date. The data science python community has settled on Gradio.
The sweet spot of Django seems to have disappeared. Jobs for Django are lower paying, and often more high stress than .net or other languages.
Django has a great outreach with it's Django Girls, Afro-Django and Django Foundation. However I feel like it's technical side needs far more love, the source code needs some major refactoring and cleanup.
I thought about this indepth on whether to send my daughter to django girls, or just train her in .net and c# myself.
can you please expand upon this argument? you didn't really try to convince anybody.
This partially matches my experience.
I see Django mostly being used for prototypes, which then become "the monolith" that allows the company to grow to the point where smaller services - or dare I say "microservices" - are more appropriate. There are a couple of things that stand out to me about that use case, though.
First, Django allowed the company to build a product and grow its business to this point in the first place. Without Django, it would take significantly longer to build things. Early stage startups are all about implementation speed; they often end up building several iterations before finding traction. Django's "batteries included" approach means you end up with experienced developers who can very quickly build out a green field services with it. You also get a hiring pool of people who are able to come into a project and be productive very quickly, since the architecture is well-defined and shared by projects they've worked on in the past.
Second... monoliths rarely die. I've been doing this for almost twenty years now. I've been through multiple rewrites and initiatives to break up an existing monolith. They very rarely succeed. My recommended (and by far, my preference) approach is to impose an informal "new feature freeze" on the monolith, build out new functionality as new services using the most appropriate tool for each, and slowly shrink the monolith. Over time, as core features are maintained, they can be more cleanly separated conceptually from the rest of the monolith. Eventually you'll get to a point where it makes sense to split off some existing features into their own services... but you'll likely never get to the point where the monolith is actually gone. Once the tech debt is reduced to the point where reducing it further is no longer the most impactful thing you can be doing, it doesn't make sense to "finish". The result is that even very mature companies that were once startups end up still needing people to work on Django projects.
> It's third party ecosystem is basically dying (especially noticeable when compared to ruby on rails).
Is it?
Sure, there are fewer shiny new projects these days. If you only look at tech news, you might see fewer Django extensions and such being announced - but that doesn't mean the ecosystem is dying. It means that the ecosystem isn't rapidly growing. In this case, I'd argue that's because both Django itself and the ecosystem surrounding it are mature. There aren't a bunch of exciting new packages being released because the packages that we already have are working well enough that there isn't a need for more.
> Job hiring for Django is disappearing from the non startup arena, which is especially bad for career developers since you need a career pathway.
I'm ~40. I've been a professional developer for twenty years, and have worked for startups exclusively for ten years. I feel absolutely no need to "settle in" and specialize in a single framework. Or even a single language. While most of my experience is in Python, I've built (work) projects in Clojure/Clojurescript.
I've taken jobs where I'd never even encountered the stack they were using. I recall one interview in ~2018 where the job was leading a team refactoring a Scala monolith into microservices. The first of those were in were in Scala as well, but they were having trouble hiring. Very few candidates had Scala experience, and not many more were both capable of learning it quickly and interested in doing so. I literally searched for Scala examples in my Zoom interview, while sharing my screen. After skimming the Wikipedia page I confidently told them it wouldn't be a problem. They seemed shocked at that, and the rest of the interview was my collaborating with them on a minor ticket they were currently working on - I was able to show that I could read Scala (even though I'd never encountered it before), ask good questions, and came to the same conclusion they did on how the change should be implemented.
A couple of months after joining that company, I saw that the mobile side of the engineering team was slightly overstaffed while the backend team was understaffed. The mobile team were using Kotlin for the Android app; I suggested that we write the next service in Kotlin and pull in a couple of volunteers from the mobile team to help. It went great.
My point is that a "career pathway" means different things to different people. In a large company, specialization is valid and often a great path forward. If you want to work at smaller companies, it's really not. The frameworks that you've used, the languages that you've worked in, even the industry that you know - all of them have a much lower bar to being replaced that you'd ever think if most of your professional life has been spent in "corporate" jobs.
If it's able to survive other 3 or 5 years, I'd argue the pendulum will just swing back to the "django's way".
> If you want an admin wrapper around your database, you have better many modern alternatives (I use directus). If you want low code and easy platform, you have bubble.io. If you want an easy api for your database, you can use things like hasura. If you want python frameworks, try fastapi (its third party admin is great). If you want an orm, sqlalchemy gives you more bang for your buck.
And your requirements.txt or poetry.lock file grows and grows. The thing I really like about django is that I don't need any external packages to start. I have basically everything I need to start inside a single package and don't need to bother about how to integrate sqlalchemy with flask, how to add auth and authorization to my stack or how to check that all of my tens of dependencies are safe and regularly updated.
The only thing I really miss is something like LiveView. I know there's htmx and similar, but i hope they will be some "official way".
Having used Django on and off for ten years or so I don’t perceive the ecosystem to be dying–the last large project I worked on used dozens of third party Django plugins and only one or two were unmaintained, and even those had some active forks happening.
You’ve also entirely missed the point of Django admin. It is not your app. It is not your project. It’s intended as a crutch. The fact that it integrates with your ‘front-end’ code, in a way that a no-code platform popped in front of your database does not, is literally its main selling point.
I've worked in the industry for over 20 years now, skills are transferable only to a degree. If you are applying to a corporate job, the person with c#/.net has the edge over someone with the equivalent experience in python/django.
Developers hate admitting this, but tech stacks matter to your hiring potential. My daughter can learn teamwork and other skills from the billion other kid oriented groups, for programming skills I'm going to help her get the easiest best paying job.
Why would anyone want that? This sounds bland and boring.
If.
I spent seven years working a corporate job. My pay is higher today working for startups than it would have been if I'd climbed the corporate ladder. I've had a couple of windfalls in that time: a ~$50k payout when an investment round occurred prior to an IPO, and a ~$125k payout when that IPO happened after I left. If I had joined that company earlier, more aggressively exercised my RSOs when I had them, or had stayed until the IPO occurred, I would have seen a ~$1.5m profit. I learned from that, and now choose my employer based on my estimation of their chances at a successful exit in the time period I want to commit to the company. For me, that means choosing earlier-stage companies where I can accumulate more equity. A happy side effect of that is that I have a much larger relative impact on the company's direction, which keeps me interested and engaged in their success.
In other words... I have no interest in a corporate job. I know I'm far from alone in that.
Broadly speaking, corporate jobs offer a higher salary relative to startup jobs.
This is by design. Being engineer #0 at a startup is far less stable (i.e. riskier) than being engineer #65535 at BigCorp. The salary is somewhat lower because the company simply doesn't have the cashflow to pay more. Startups have one thing to offer employees to offset that lack of stability and lower salary: equity.
The vast majority of the time, that equity ends up being worthless. Every once in a while, it becomes worth a life-changing amount of money. It's not fair to say that Django jobs pay less. Those types of jobs are an opportunity to trade a portion of your earning potential for a few years for a chance at a much larger prize.
I don't have numbers in front of me to be able to prove it, but I'm of the opinion that when you include this in your calculations, the expected value of your labor is higher working for startups than at large, established companies. While the chance of any given startup succeeding is relatively low, it's not unreasonable to think you'll be able to join up to a dozen or so over the course of your career. The chance of _one_ of those having a successful exit is high enough that I've staked a big part of my financial future on it happening.