Hacker News new | ask | show | jobs
by godmode2019 1907 days ago
I'm more if a flask man myself. Worked with django only when I had to.

Maybe I'm wrong?

16 comments

Depends what you want to do, and why you're doing it. Very often when I make something in Flask, I end up with so many dependencies it might as well be Django (but without the cohesion). On the other hand, Django might be overkill in some situations (e.g. a small API without a relational database backend).
I was forced to fall on this trap once: a guy has a small Flask app up and running, and he asked for help to implement: an ORM with migrations, an Admin and form validation (among other things that had nothing to do with Django such file parsing).

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.

I like to paraphrase Greenspun's Tenth Law in this context:

"Any sufficiently complicated Flask app contains an ad-hoc, informally-specified, bug-ridden, slow implementation of half of Django"

I love the paraphrased quote. It’s a bit ironic in that Python programmers love the batteries included standard library but quickly jettison that idea when it comes to Django vs Flask.

Flask’s marketing of a simple route decorator makes it seem light weight but once you add everything else it becomes Django.

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...

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.

I think one common misconception is that Django can't be used in place of Flask when you want a minimalist set up. And to be fair, I used to think the same until I read Lightweight Django [0]. Their smallest django project code is just a couple of lines:

    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...

I think the comparison is not so much lines of code but conceptual overhead. With Flask you create an app instance and call @app.route() with some Python functions and run the app. Granted it's probably not going to do much, and by the time you build out a real-world application with a SQL database, authentication and so forth you're going to get diminishing returns, but for a beginner who just wants to know "how do I make a web page using Python?" it's great.
How big is the smallest Django project after you add proper authentication (signup, login, pw reset, oauth2, 2FA)? Last I checked it was rather terrible.
Django has a substantial learning curve and you may need to spend more time to get started. But ultimately to do the same thing in Flask you have to spend comparable time to learn, except that Flask lets you start much quicker into your learning. As your Flask project grows you find out it is not actually that easy nor convenient. This is of course my experience only. I decided to just stick to Django (and DRF) and I feel no need to use anything else. For performant services I use Go.
I'm more of a Django man, worked with Flask only when i had to. There's no "wrong" or "right" in this…
Then why not work with PHP?
There’s nothing wrong with PHP. And Laravel is very popular for good reasons.

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.

I generally agree philosophically but PHP has a couple of features which make problems more likely: the C style error handling increases the odds of problems being ignored (yes, Python can have except:pass but that’s more obvious & requires intent) and the mushy typing hits even experienced developers who didn’t think about whether they needed === instead of ==. The standard library’s inconsistent parameter ordering for related functions probably deserves a mention here, too.

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.

I think the tooling we have in the Python ecosystem far exceeds PHP and I agree (and mentioned below) about the inconsistencies.

Been a long time since our chats at DC Python. Hope you’ve been doing well, sir!

Heh, yes, it has been quite a while. Pandemic pre-K has been quite the adventure so DC Python seems like a fairly distant memory ;-)
> There are people out there writing Python just as bad as what you think of as bad PHP.

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..

Sure. It’s up to the end user to use the tools in an appropriate way.

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.

Then lets look at those semantics: what is bad, and is anything ever bad? Because I think mostly all frameworks are pretty easy in the small, it's how they help/hinder with larger projects that demonstrates their worth.

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.

Django has a few drawbacks:

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.

For (1) The simplest is probably just running a Django management command - maybe from a cron job.

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?

> 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.

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.

For 1. I have found that a custom admin command can go a long way. If you want to be more "reactive" have a look at this asgi/channels thing... That or custom pythons scripts with the caveat of pointing correctly the DJANGO_SETTINGS ... As for 2. Well... Basically every ORM no ?
I'm using nameko and Django in a project, and haven't seen any issues with nameko just calling django.setup() and then the models and managers.
I've had the opposite experience, working smoothly with Django for a decade except for one huge Flask project. Which essentially re-built Django... badly.

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?

There's more choice in the flask ecosystem, but then again, you can suffer from poor choices and a lack of architectural consistency.

I'd say the big thing is SqlAlchemy for Rel DB. and Maybe alembic to compliment.

I also used Flask and I wasn't a Django fan. But this got me on larger projects, when Django and his "Batteries Included" made sense. Now I will soon think about the size of the project in advance, and based on that I will choose Django or Flask. There really is not something wrong here. Everything has its pros and cons.
Right tool for the right job. You’re not wrong unless you are - if as others said you’re reinventing the wheel on flask, or are doing a very simple API service in Django which doesn’t use most of its facilities (like the admin) and could easily be done in flask.
Honestly, I don't see the point of using Flask anymore. You can set up a Django project and just use a single module with a bunch of view functions, built-in testing and sensible defaults. Done. Not choosing that approach just because it takes a few more MBs on disk or needs a few more KBs of memory is shortsighted, IMO. You can't always predict what a project will end up needing.

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!

why would you use Flask instead of Django

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.

Because Django is pretty badly designed, and it can get in the way when you need to do some more complex stuff. It get's the job done for 95% of cases, but that extra 5% can devolve into some pretty nasty stuff.

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.

You can use whatever ORM or templating library you want. But at least if one day you realize you need something that Django offers out of the box it's there for you to use.

And if not it's not like it has any perceivable effect on performance.

> I'm legitimately asking: why would you use Flask instead of Django, even if you don't (but might) need the ORM, admin etc.?

If for some reason you wanted to use a noSQL database, Django's ORM and everything connected to it (like admin) won't work.

There are connectors for noSQL databases as well. Or it's surely easier to implement one than to reimplement everything else around the ORM.
As a rule of thumb, Flask is good when your app will only ever need to be a single file. Otherwise, as other commenters have said, you're basically reimplementing Django badly.
At some point using Django just makes more sense.

No need to reinvent the universe for bigger jobs.

I feel the same way. I like simple frameworks like Flask, Starlette, or FastAPI. Django feels too heavy for me, though I get why people like it. Maybe I haven't learned it well enough, but I often feel like I'm having to do weird things or fight the framework to get done what I need. Simpler frameworks fit my mental model better.
I owe a lot to Django as it was really the thing that got me into backend programming by leading me to learn python in early 1.X days. My first real programming job was backend django programming for a newspaper. Eventually things shifted towards django-rest-framework, flask, and now my go-to Starlette. Haven't used Django in some time but really appreciate the project and happy to see it moving along.
Same here. Django 0.96 at the Washington Post.

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. :)

Congrats on the new job! I never really dabbled with Go, but a team I was on recently worked with a backend written in Go, and I was present in lots of discussions :) For current project I'm using Starlette/asgi, but I'm sure Go would have some advantages
You should try it, it’s really all batteries included.
The ORM is horrendous.
Can you elaborate? I've been using it for years and it mostly does what I want. It's an ORM and obviously sometimes generates unefficient queries I need to manually amend/refactor but otherwise I don't see any major issues with it?

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.

Comparing Django vs SQLAlchemy, Django's weakest point is its extremely static ORM syntax. The double underscore separation (e.g. user__group__name__icontains) for query parameters is likely my biggest pet peeve as it requires me to unroll unchecked strings together into a big garbled mess. I would have much appreciated being able to use more code-verbose query tools; the moment you have to go into building more dynamic user-defined query systems, Django's ORM just becomes a hindrance.

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 inability to batch network calls in a single unit of work makes the ORM needlessly slow. That's also one of the main advantages to managing transactions/session yourself. It can save a huge number of round trips in a complex view.

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.

The only thing I don’t like in the ORM is that it doesn’t force you to use transactions.
I doubt you're wrong. There's certainly a large set of problem that can be solved equally well by either framework. There are also projects where one is clearly a better solution.
Django fan here. You are not. Several frameworks exist to satisfy several needs and profiles.
Anybody use CherryPy?