My advice - keep it simple
- function based views
- centralize access to the ORM (avoid fat models, use a service layer)
- responsive bootstrap template with crispy forms
- minimal js
- 12 factor type setup - django-environ or similar
- be aware of n+1 select problem (I use django debug toolbar but looking into django-zen-queries)
- plop it on heroku, AWS lightsail, Digital Ocean or if containerizing use AWS Fargate
- avoid celery unless you are at a scale you need it - use django-cron, django-db-queue or similar
- use a managed database and managed email service
I have had zero scalability problems. People say Django is slow but it handled 10k active users on a small EC2 instance without any issues (static stuff served via cloudfront)
Class-based views, in their most basic form, are a lot easier to read. E.g. look at the DRF CBVs I have here:
https://github.com/Alex3917/django_for_startups/blob/main/dj...
If you can avoid Generic CBVs (things like ListView) and inheritance, then the only difference between FBVs and CBVs is that CBVs make it easier to see what's a GET / PUT / POST / DELETE by adding some syntax highlighting that makes it easier to visually differentiate which code goes to which method. You don't need to know anything about classes in Python in order to use them.
It's not at all difficult to switch from FBVs to CBVs later, and most people (myself included) use FBVs when getting started. But I'd also say that if you're willing to push through the initial discomfort and spend the extra half hour or whatever on YouTube in order to understand them, then you do get a little bit of a nicer overall development experience.
That way my actual view logic doesn't have to deal with anything http, and it makes testing them way simpler.
I had not heard the term "fat models" before so I googled it. It did not go in the direction I expected.
Combined with the Repository pattern from DDD, you can have all your model fetches go through a separate class that does the necessary select-/prefetch-related calls, then seals. (Or just override your model's Manager to do this).
And we have a coding standard guideline to discourage using queryset operators in business logic, as you note it breaks encapsulation and makes your code really hard to refactor later. This is hard to enforce though…
I think Django’s ORM is if anything too convenient - it’s great for the first 100kloc but then as you say, you need to overlay some discipline to prevent things from blowing up, and the framework is all about removing friction which makes this hard.
I'm not saying that you need micro services, but you should find a way to split this up into a few applications with well defined interfaces between the applications.
This is what I always found in Django projects with the notable exception of the one that had only one giant app.
I started to believe that one project doesn't get along with multiple apps (kind of microservices) in the mind of the average developer. Only one app Rails style is probably easier to grasp and manage.
What managed databases do you recommend that adequately meet price/performance needs of indie developers?
- WAF rules
- EC2 instance
- RDS
- Cloudfront
I use fargate when deploying now to get out of box management
Here is a fresh example: they deprecated CELERY_ prefixes in Django settings for some reason, which makes zero sense [1]. But because it's Celery, they only warn on a few properties but not others, and the tool they ship inexplicably renamed completely unrelated settings for me [2]. And yes, apparently the new way doesn't work either [3].
It's very characteristic of what I've seen from Celery over the last few years of working with it. If you are doing anything greenfield, it's best to avoid it altogether.
[1] https://stackoverflow.com/questions/65554242/celery-imports-...
[2] https://twitter.com/lambdadmitry/status/1468337594358546435?...
Covid screening application (sold)
Inventory management (initial clients in alcohol beverage bottling/distribution)
In Python, there are micro frameworks like Flask, and whatever new ones claim to be "Blazingly fast!", async etc. Once you get over the learning curve, Django seems the nicest to use, due to including features like an auto-updating ORM, email, authentication, admin page etc. None of the Rust frameworks, in contrast, come close to feature parity.
Django's feature base is vast, and I admit I don't understand much of it. You can choose the feature sets you need. The template language is inflexible, but you can smooth this over using JS instead A/R.
We've already been hit by multiple bugs with fixing PR opened, but left to rot, and missing documentation : the 'tutorial' documentation is great, but if you want a reference you have to go read the code.
I guess that's the issue when you pick projects maintained by one person, so for my next projects I might get back to something built on stronger grounds, like Django.
How is Django this day with modern Python constructs like typing in general and Pydantic models integration ?
If you want to see faster progress, there are several ways to help, they are all documented here: https://fastapi.tiangolo.com/help-fastapi/
One of the things that consumes time the most is handling issues by others. If you go and help them and they close those issues, that's a lot of minutes (in some cases hours) that you save me, and that I can then dedicate to review the other issues and PRs.
Seeing this kind of topic fairly frequently, it would be great to understand the short/mid/long term plan for the project in terms of governance.
I guess we can all agree that having a single maintainer on a +40k stars project with huge adoption (amazing stuff btw) is unsustainable and extremely difficult, and can drive people away from adopting it in big corporations (I've seen a few comments on Github that mention this), and can make early adopters eerie.
I honestly have no idea on how to do that, but some other projects have been able to (fairly) successfully descentralize the development to be able to keep pace with the development.
It's obviously fair and understandable if the long term will still depend entirely on you, being the creator, you obviously have 100% right to do things the way you want, and nobody can argue against that.
I guess it could be helpful to give the community some guidance on what's the idea for the future of project, and whether it will have a more distributed governance or if it will continue being centralized.
Any of those paths is fine of course, I guess it would just help people deciding the framework choice for the future.
How is creating PRs going to get us "faster progress" when the very complaint from OP is that PRs are left to rot? And some PRs as simple as 1-line critical bugfixes that have been rotting for over 3 months? See, e.g., https://github.com/tiangolo/fastapi/issues/3665#issuecomment...
Shouldn't open PRs be prioritized over open issues anyway? Folks have put in the effort to not just complain about, but to FIX the bugs, and they are ignored.
I believe there's a third-party package "django-stubs" that provides type hints for Django code. For your own code, it's just Python in the end so you can type-hint it as you normally would.
> Pydantic models integration
There isn't as far as I know. Django has its own model layer however unlike Pydantic, Django's is purely for the DB level, it's not there to (de?)serialize JSON.
In the Django world you'd typically use Django Rest Framework serializers for that. Now you can use Pydantic and it probably won't be too much work to make them work with DRF, but whether it's worth it is a different matter - DRF gives you a lot of stuff for free such as auto-generating serializers based on DB models (including validation and everything) which you wouldn't get with Pydantic.
Meanwhile, sponsorships are at 13% of the (not terribly ambitious) goal of $6k/month [0].
Yeah, that's why.
[0]: https://github.com/tiangolo/typer/
I tried a few tools in FastAPI, and it's fantastic for those, but I think I'd still stick with Flask for something more well rounded (not just as an API server).
That said, FastAPI seems to have a lot of issues and the maintainer doesn't seem to be responding to the numerous PRs that are piling up. I'd much rather just stick with Django at this point
We use SQLAlchemy for database interaction, a lot of direct usage of Pydantic, Celery with RabbitMQ/Redis for task processing. FastAPI provides a really lightweight interface to gluing pieces like this together.
- Faster in general than Flask (thanks to starlette / uvicorn)
- asyncio libs in Python are generally beating out others in terms of perf (e.g. asyncpg vs psycopg2). This isn't to start a whole "asyncio is faster" flamewar, not saying that's necessarily true. Just that it seems the people who are building in asyncio are also people who care about perf, which I do as well. The (non-asyncio) Python community has neglected perf for a bit too long imo.
- asynchronous style works much better with things like WebSockets, which we use
- Auto-generating an OpenAPI schema[1] is nice to have.
- Using type hints for things simultaneously encourages mildly "safer" code while also giving better auto-complete suggestions
I made the mistake of picking Flask for a really big project when these microframeworks were a fad and everyone was dismissing the big ones like Django and RoR. That was a very costly mistake. I learned the hard way provides way so many things out-of-box that I always took for granted but I had to manually implement in Flask.
Take tests for example, Django automatically makes sure that any DB operation is cleaned by the end of the test. That's sometimes that I never gave a thought until our Flask tests started leaking everywhere. The way that Django handles that problem is very clever and we had to manually do it Flask.
It pulls together Django, Docker Compose, Postgres, Redis, Celery, Webpack and TailwindCSS. It's all set up for both development and production. It's also been updated to use Django 4's new built in Redis cache back-end instead of the django-redis package.
I have things split out where the Webpack dev server runs in its own container only in development. It uses the Docker Compose override pattern to skip it in production along with Docker's multi-stage builds to ensure production assets get built and digested with collectstatic when DEBUG is set to false.
I gave a talk this year at DockerCon on a whole bunch of patterns I use with Docker Compose and my Dockerfile to get dev / prod parity without duplication and overall best practices.
The video and blog post of that is at: https://nickjanetakis.com/blog/best-practices-around-product...
It walks through a live demo (0 slides) going over a Flask example app but it's 100% the same for Django.
Then I went through a couple of (depressing) years of using Java/Spring professionally, and recently I made the choice to move to Elixir/Phoenix. It’s going great, and I don’t think I would go back to heavy OOP if I didn’t have to.
Some things I really miss from Django:
- Models with more centralized validation logic. In Phoenix (and somewhat similarly in Rails), you need to edit your migration, schema, and changeset. In Django, you edit your model and the migration can usually be made automatically with no need for a 3rd-party package.
- Django REST Framework. You can get pretty far with an app just by leveraging ModelSerializers and ModelViewsets. It’s ridiculously elegant, simple, and powerful.
- The Admin layer is fantastic and unparalleled.
Some things I wish Django would add/enhance:
- Making it more clear when you’re going to hit the database (explicit is better than implicit).
- True async up and down the stack. Not a small task within the Python ecosystem, but I think for folks who are not already invested, looking at Elixir/OTP/Phoenix is too tempting. If you don’t have kids to transport with you, a Lambo looks much more fun than an S-Class Sedan.
You might like https://github.com/dabapps/django-zen-queries
Gives you fine grain control about database queries
This has been in the works for a few years. Everything in Django works with async except the ORM at this point. Which in practice, means it's not really async. But hopefully they are getting close.
[0] - https://avi.im/blag/2021/rc-day-20/
14 years ago someone helped me discover Python and Django.
I started from django official tutorial and never changed the framework of choice.
It was my hobby, my career, my tool to put the food on the table.
12 years later I have started building a way to solve deployment question.
started from bunch of scritps. today I have made cost effective tool to deploy Django projects and pretty much any python app on AWS/Digital Ocean
it is like heroku but uses you own cloud account and not expensive at all.
I don't think I overstate the relevance of what Django did by saying that Django almost single handledy advanced the state-of-the-art of web deployment in Python forward a decade.
Of note, in my opinion :
- The new AddConstraintNotValid operation allows creating check constraints on PostgreSQL without verifying that all existing rows satisfy the new constraint, meaning that one can now create constraints on big postgres tables without a waiting period.
- Async methods are coming, to cache for now but hopefully soon to the ORM. They are prefixed with a `a` in the name
- DeleteView now uses FormMixin, allowing you to provide a Form subclass, with a checkbox for example, to confirm deletion. In addition, this allows DeleteView to function with django.contrib.messages.views.SuccessMessageMixin. This is a big thing if you use DeleteViews, as you can now easily show a message post-deletion to the user.
I (wildly) speculate that once the ORM is async too, and all the rest of the bits fall into place (maybe django 5?), maybe django 6 will drop the `a` prefixes and integrate it all back together somehow?
Many thanks to everyone involved in the project!
Just for reference: The latest release for Django Rest Framework is not compatible with Django 4.0 yet. At least my first attempts failed due to a missing `pytz` dependency. This is fixed in the `master` of DRF on Github. Installing `pytz` explicitly again to your project fixes DRF for now.
Saw this in the extended release notes:
https://docs.djangoproject.com/en/4.0/releases/4.0/#zoneinfo...
> The Python standard library’s zoneinfo is now the default timezone implementation in Django.
> This is the next step in the migration from using pytz to using zoneinfo. Django 3.2 allowed the use of non-pytz time zones. Django 4.0 makes zoneinfo the default implementation. Support for pytz is now deprecated and will be removed in Django 5.0.
> …
> To give time for such an audit, the transitional USE_DEPRECATED_PYTZ setting allows continued use of pytz during the 4.x release cycle. This setting will be removed in Django 5.0.
I've written about this before. I think the stock Django dev configuration needs to change to something that is equivalent to a reasonable deployment on a common VPS, whatever that means. The development server is a nice trick, but the things you have to do to move to a real server are painful. Same with SQLite. Why not come up running PostgreSQL by default?
I am sure there are varied opinions on this. All I have to say is that, over the years, I developed a document to help with deployment on standard hosting platforms, like Linode. It is staggering when compared to the experience of deploying something like a Wordpress/PHP site on the same or similar platform.
This, from my perspective, is the weakness for Django, everything else I love and enjoy.
systemd service + gunicorn is not that bad, I think. You can have simple deployment and graceful restarts[0].
Ime, adding a docker-compose and a couple Dokku commands on the server is the best experience I've seen so far.
[0]https://www.digitalocean.com/community/tutorials/how-to-set-...
Whatever the case may be, I can take a single VPS and multi-host a bunch of domains, each with it's own Wordpress installation, DB, etc. Virtual hosts makes this possible. It's stupid simple. Getting a single Django application running under a single domain on a VPS is a nightmare. Particularly when you consider everything you have to do to migrate from the development environment to production.
This is why we do not do any Django development using the standard installation and go right wo running it just like production on either virtual machines or a dedicated on-premises Linux server. The development environment is as close to an exact match as the production environment. No SQLite, no runserver, no nonsense with static files, etc. This is what I think the Django project needs to really think about working on. There is no reason to have a crippled development environment at all. The base installation ought to be setup to migrate to a standard Linux host (not something purpose-built like Heroku) without much friction. If you are doing a more complex site with multiple servers, load balancing, etc., you are on your own.
I truly think adoption would be far greater if the deployment experience was sensible. I have talked to people who absolutely gave up on Django because going from development to production was a nightmare without spending money on far more expensive servers and services they should. This is an application (Django) that should easily run on any Linux server. The fact that companies were created to facilitate deployment says it all.
76 days ago https://news.ycombinator.com/item?id=28609188
3 month ago https://news.ycombinator.com/item?id=28566044
Maybe the libraries need to cost 30,000$ ;-)
Choosing between software (especially bikeshedding between languages that both place priority on being pleasant to write) is often like comparing a Tacoma to a Tesla on the quality of seat heaters, upgrade price for the sunroof, and selection of factory paint options. Worse, you can't often have a clear understanding of the difference without investing the time to gain direct experience with each option. Otherwise, you're relying on community reputation and hoping it's both accurate and not horribly out of date.
At least if you're in a EU backwater country or in EU public sector-related projects. (Which usually means java/c# and to a much lesser extend a python tech stack).
PS: Loved the rant but you forgot to mention Golang :). "You're doing web backend and not using Go?!!"
I have a side project / website that I want to work on. I have over a decade experience with PHP and JS in various forms, but am willing to try something new.
The idea of compiled languages don't appeal to me, so am not really interested in Go, Rust or Dart. It looks like either Django, Elixir, or PHP - but am open to other ideas.
Anyone with enough experience to tell me confidently that it is worth Django or Elixir? Anyone can give a five line overview of the differences vs PHP or Node?
And along the way, am I the only one who is confused by what seems too many environments and package managers? (from venv/virtualenv[1] to pip/easy_install to wheels/eggs)
Elixir: Technologically "mind blowing", although all the nice things come from the Erlang VM and not from Elixir itself in my opinion. You will likely not find any job using Elixir, if you do it is going to be full of people just learning the language so the codebase will be very likely a disaster. You will miss a lot of libraries and you will have to write code for things you'd take for given in the PHP ecosystem. Be ready to fight your editor plugins (depending on which one you use, and the degree of IDEisms you're used to).
I understand you want to learn something new, so the most "radical" one here that will teach you more new things is clearly Elixir.
But other than learning purposes, If I were to build something for real, I'd stick with PHP and Laravel, it's an incredible productive, well documented and well thought out platform to develop in.
If you’re good with Laravel for example, no need to switch to Django or Elixir and vice versa. Stick with what you know and you’ll be a happier developer.
Laravel is a real "full stack" framework, it has a very powerful templating system (one of the best I've seen!) where you can do components instead of just includes. It has a powerful assets bundling pipeline, great integration with alpine, Vue, inertia and the super awesome livewire.
Laravel documentation is TOP.
As I'm not a fan of the SPA approach and still like frontend and building applications, I much prefer Laravel nowadays.
(Not cannonfodder, I am genuinely curious)
In terms of how they "feel" to develop with? About the same. Similar ideals - skinny models, service layers, REST-first but you can make it RPC-style if you want...
Thanks.
If you are learning both language and framework from scratch, check the local job market. 5 years ago in the Bay Area there were roughly 2x as many Rails job postings as Django, though I doubt it is this lopsided now. Also Python is used more broadly than Ruby, eg for ML and scientific/numeric work.
I guess the only takeaway you can get for that is that Django, at the very least, works fine, and probably will solve the problem you come in with unless you want it solved in a very specific way
If you need anything related to ML or the sciences, go Python.
The reason I switched is more or less entirely that I hit performance issues with the Python Graphene library being really slow at returning larger datasets, and couldn't find a solution in a reasonable time frame.
My impression was that Django has a much more powerful and pleasant ORM – your migrations are derived from your models, so if you want to add or remove a field (for example), you update the model class then the migration command works out what it needs to do to make the database match the models. Rails works pretty much the other way – you create explicit migrations to add/remove columns, and the database is the source of truth - your model classes don't even have explicit accessors in the code for the fields you define in the DB. I found the Django way more logical, and I found things like many-to-many relationships much easier in Django, but the Rails way isn't too bad once you get used to it.
Rails is well known for being heavy on the "magic", which is quite expressive once you get used to it but I find it hard to know where to look if I want to e.g. know what methods a model has, whereas Django felt a bit more explicit in this regard. Personally, I find Python a more pleasant and easier to read language than Ruby, which has so many ways to express the same concept in different ways, but I am actually warming to Ruby.
If you're interested in adding type checking, it seemed that Python has better and more mature options here.
Ultimately though, for what I wanted (which was to build a backend with sensible defaults out of the box and really write as little code as possible), I think Rails is a better fit. The ecosystem of libraries seems more mature and better documented (I hit quite a few issues with Django related libraries which took a lot of Googling and some hacks to solve). The Ruby GraphQL library is much nicer to work with and much more performant.
The amount of code I have to write is generally pleasingly low (though I'll admit it's quite spaghettish already, I have been learning Ruby as I go and I can totally see how a large codebase could become a mess), and it's easy to Google for most stuff, and the defaults seem pretty sane. I will say on a slight tangent that I recently enabled GitHub Copilot, and am finding it surprisingly quite useful in a Ruby project, where I often struggle to know/remember the right syntax!
So... that's my experience. Ultimately it came down to a niche-ish requirement (performant GraphQL API) to force my hand, but I think I'm pleased with the end result. Both are impressive frameworks and I don't think generally you could go too far wrong, but for me Rails just feels that bit easier and more mature for bashing out a solo project.
Let's see what version I'm running: Django 1.5.9
This is going to be very painful isn't it. I wonder how long until the bitrot makes it unbuildable and undeployable.
I should clarify, there is no database attached to this and it talks to a secure API that is maintained really well. So this is just views and templates, where the views talk to the API.
I believe the middle part of the learning curve can be easier, but with the "social cruft" of all the Django tutorials out there, it's a game of luck to encounter what's good and what are the different, sensible, approaches to handling growing/big Django apps.
What can make this easier is a document/discussion of some sort that provides clear, complete, approaches. Here are some aspect that needs to be considered. I believe with the combinations defined, and describing the tradeoffs will be a very great start for any team/person looking to jump into Django, or improve their next project.
- Postgres seems to be default. SQLite + Litestream is there but still bleeding edge.
- Packaging is the hot topic, for sure. Pipenv, poetry, venv, etc?
- Traditional Serverside Templating + JS enhancement (HTMX/Hotwire/etc), or JS based SPA (React, Vue, Angular, Svelte, etc)
-- This also includes the asset compiling story (Tailwind JIT, Sass compilation, Babel/webpack/rollup/etc)
- Fat models, Fat views, or Service layer? To which extent?
- Single app (Doordash) or Multiple apps (Thread with >500 apps)?
- What's the theoritical limit to using Postgres + Disk/Memory Caching (so no external Redis/ElasticSearch/other services needed)?
-- Search, queues/async job, scheduled jobs, reports, emails, etc
EDIT: A view additional points
- Documented limits about using whitenoise to serve static assets, and when & how to move to S3. Also Cloudflare/CDN fronting
- Cloud storage story (uploading to S3 api from FileField and Rich Text fields, and also async jobs)
-- Proxy story to enable <a download> from cloud? (Maybe a bit far, but I think this is a common request)
- Deploying/Serving optimization (is gunicorn the best option for now? how to scale w/ regard to vCPU counts to avoid the 25% CPU Max utilization?)
- How to debug between inefficient query/app code/templating/serving/caching?
I'm sure there are more points, but it would be great if there's a documented sensible approaches to evaluate. I know there are templates, but great discussions about the tradeoffs of complete "packages" are rare.
In the Phoenix ecosystem you bring each of those pieces in as you please (auth generator, Ecto + other libraries etc). So I would say if your really want to move fast, you will still get further, faster with Django - but the trade-off (as other posts here have alluded to) is that once you need to implement custom features or optimisations you will often fight against Django (or need to wade-through half a dozen classes in some inheritance tree to find the right hook).
Another big difference between Phoenix and Django is that building websocket services in Phoenix is an absolute breeze. The Elixir runtime maps perfectly onto any type of messaging service.
Elixir is dramatically more performant and will scale better. A lot of people enjoy Elixir more or find it conceptually more interesting than Python.
IMO the number of packages and facilities provided by Django will outweigh Phoenix's performance for 95% of users.
And although it might be different form what you're used to, I really like it. If you check their documentation, you can see exactly when they'll make breaking changes and features will be deprecated and removed.
I was hoping for some progress on async ORM as well. Is there any word on when this is coming?
Plus it already has decent async support.
I doubt that's true, but yes, having DRF merged in would be rather nice.
Now I have to go and check what to update for Deployment from Scratch :D