Maybe I'm wrong?
Maybe I'm wrong?
I suggested to migrate the app from Flask to Django while it was small and simple, but he refused for Django is "too big and complicated". OK, then. We ended up creating a monstrosity of Flask half-assed packages to include functionality that is already included in Django (think cache, csrf, admin...), plus WTForms, plus SQLAlchemy, plus Alembic, hard to test, hard to keep updated, hard to deploy, and so complex that it turned non-migrable to Django. Development felt like walking through mud.
Heh. I've done that. Impressive how quickly you can go from "I literally need three or four REST end points to let users query this SQLite database" to, well that.
"Any sufficiently complicated Flask app contains an ad-hoc, informally-specified, bug-ridden, slow implementation of half of Django"
Flask’s marketing of a simple route decorator makes it seem light weight but once you add everything else it becomes Django.
import sys
from django.conf import settings
settings.configure(
DEBUG=True,
SECRET_KEY='thisisthesecretkey',
ROOT_URLCONF=__name__,
MIDDLEWARE_CLASSES=(
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
),
)
from django.conf.urls import url
from django.http import HttpResponse
def index(request):
return HttpResponse('Hello World')
urlpatterns = (
url(r'^$', index),
)
if __name__ == "__main__":
from django.core.management import execute_from_command_line
execute_from_command_line(sys.argv)
Granted, it's not as terse as Flask's hello world example but it's still quite short.[0] https://www.oreilly.com/library/view/lightweight-django/9781...
There are people out there writing Python just as bad as what you think of as bad PHP.
One dev I knew insisted everything must be a list comprehension — including all for loops in regular flow control. That was Not Good(tm).
———
Edit: please read the parent comments for context. GP said there’s no right or wrong and OP said then why not use PHP and I said it’s not wrong.
By that logic: there are people "out there" jamming pencils up their noses, therefore a shovel is just as good a writing implement as a pencil..
There are a ton of inconsistencies in the PHP standard library and I’m not defending that but that doesn’t make it “bad” as you insinuated.
On that basis, sure, it's up to the user to figure out what's appropriate; and a shovel is not an appropriate writing implement - you could say it's even a "bad" one.
I started using PHP around 1998 and quit cold-turkey about a decade later for Python after noticing across the board quality improvements on every project. PHP isn’t terrible but using it requires constant diligence and few teams had the extra time and skills to use it safely.
Been a long time since our chats at DC Python. Hope you’ve been doing well, sir!
1. It’s tricky to use in non-web contexts. If you ever need something to happen as a response to an event which is not a web request, Django makes this difficult and ugly.
2. Django also more or less requires ownership of the database in order to function as intended. If you want to have your Django objects in your own database and handle schema changes centrally (to, for example, alleviate problem 1 above), you must also abstain from some of Django’s power, i.e. migrations, etc.
But maybe I'm misunderstanding the kind of task you have in mind?
For (2) - you seem to be saying "if you don't want Django to handle migrations then you lose the benefit of Django handling migrations" - but again I might have missed some subtlety here?
You are a bit vague but this is where message/task queues (e.g. Celery + a broker) come into play. Celery integrates with Django quite nicely.
I later tried and enjoyed Flask for a really small solo project, so I don't think you're wrong.
Maybe there's a lot of implicit cultural knowledge on what packages work best to compliment Flask and the original developers on the big Flask project I suffered chose poorly?
I'd say the big thing is SqlAlchemy for Rel DB. and Maybe alembic to compliment.
I'm legitimately asking: why would you use Flask instead of Django, even if you don't (but might) need the ORM, admin etc.? Thanks!
If for some reason you wanted to use a noSQL database, Django's ORM and everything connected to it (like admin) won't work.
If you don't really know Django, the learning curve on Flask is a lot shallower. So if you don't need ORMs, models, admin etc. but you just want make those python scripts you wrote callable via a web browser then you'll get version 0.1 out the door a lot sooner with Flask.
Also a lot of Django kind of assumes the ORM as your data store. So if you need to use a primary data store that cannot be accessed via the ORM you lose a lot of what Django has to offer.
That being said, I agree that many 'simple' Flask projects have a tenancy to grow until you have implemented most of Django in Flask anyway.
Typically the inflection for when Django becomes a nightmare is when you want to start splitting the application up. This is made really hard because Django depends on a whole load of globals (settings, urls, context preprocessors, the actual WSGI handler). With Flask you can have two separately configured applications running in the same process, routed with a bit of WSGI middleware.
This comes in handy when you need to do a 'soft' rewrite and have code running side by side. This also just makes things easier to test, because you can build a new application object for each test with it's own settings. You can't do that in Django with out a great deal of consternation; try creating two tests with different middleware stacks in Django, patching settings won't work because the application has already loaded, and there's no way to reload it between tests.
Also, for the same reason (as someone else said) it makes it tricky to use in non-web contexts. Like Celery.
Django's can't handle more complex database queries. If you've ever seriously used SQLAlchemy, you'll know what you're missing.
The ORM is also lacking a unit of work model, which can kill performance. The only way to create multiple objects in a single database round trip in Django is with `bulk_create`. But you can't create something like a group and then a user in a single database round trip. Sure you can create them in a single transaction, but that's not quite the same, because each roundtrip takes an extra millisecond. It's an easily avoided inefficiency that SQLAlchemy solves.
The template language is limited compared to Jinja2. While this is by design, it doesn't support streaming the response back. This is really annoying if you're generating massive templates. It would have also been really simple to do.
I could go on really.
And if not it's not like it has any perceivable effect on performance.
No need to reinvent the universe for bigger jobs.
I start a new job next week at a Django shop after a couple years of JS and Go. I look forward to getting back to it but I will miss Go. :)
In contrast I've looked at SQLAlchemy with Flask and I couldn't even wrap my head around declaring models (which inherit from the DB connection object if I remember correctly, so potential for circular imports) and manually managing transactions/sessions seems unnecessarily complex.
I also noticed the second part of the comment: Django does a lot of Python magic in the background through extensive use of reflection and class-level declarations, this hides away the abstractions (again) at the propose benefit of ease of use. And well, it is easy to use. For certain applications. I just personally found a lot of footguns trying to work with more advanced Postgres functionality (mainly around JSON) and it took a while to write my own abstractions atop the Django ORM to get to a comfortable level.
The Django ORM itself is also slow at generating SQL. Recently I was bemused by a query, which took 500us to actually be generated. This wasn't doing anything particular wild, it just had a `select_related` call to an object that had about 50 fields (not great DB design, but beyond my control). The query actually took longer to build than it did to run.
That itself wouldn't be an issue if you could LRU cache the SQL query itself. But you can't, it's Django.