EDIT: To avoid hollow naysaying, here are some alternatives to Flask I find much better designed:
- Tornado Web Framework [0]
- Falcon [1]
[0] http://www.tornadoweb.org/en/stable/webframework.htmlEDIT: To avoid hollow naysaying, here are some alternatives to Flask I find much better designed:
- Tornado Web Framework [0]
- Falcon [1]
[0] http://www.tornadoweb.org/en/stable/webframework.htmlWhen I first started learning Python / web frameworks, I went with Flask because it was smaller and "simpler". As my project grew however, I had to organize it. I was basically imitating what Django gives you by default, though less cleanly.
I have exactly the opposite experience: Flask is nicer than Django; SQLAlchemy is better than Django ORM. Love a bit of Flask.
Many of these independent components pale in comparison to their Django counterparts in glaring ways—they are often a pain to use, with some pretty questionable internal code choices. They remain used because they are often the only choice out there, even though their implementations are inferior to Django’s.
I say this as someone who has used Flask for over 5 years, as well as nearly 5 years of Django.
Parts that I mentioned are (or were when I compared) light years ahead (especially sqlalchemy).
I feel like most using Flask would consider “Flask components” to be equivalent to Flask extensions—e.g., Flask-SQLAlchemy vs SQLAlchemy proper. Maybe it’s a pedantic nitpick, but I’ve never heard anyone refer to SQLAlchemy as a Flask component in 5+ years, hence my comment about the distinction. But yes, many of the Flask-compatible Python packages you mentioned are quite a joy to use.
The obvious move at the time was to move to django and I spent some time familiarizing myself with it's own DSL. But boy was i struggling all along the way to do things how I liked in Flask with django. The Django Templates were extremely limiting (no modules) and couldn't even do regular python things and I came to find that extensions for Django were in no better shape than flask's. There was no clear solution for rate limiting and various other things I was looking for.
I've followed rails from a distance for a long time but, coming from python, ruby seemed so abstract to me i could just never figure it out but towards the end of my django time, i was finding that rails did/had everything i wanted and it all worked just the way i wanted it to and it was calling to me really hard. i took a big leap and spent a couple months diving fully into ruby, doing all the tutorials, reading all the books. at this point i am officially converted and my project app with it is already further along than i ever got with flask or django. when they say "ruby/rails is built for programmer happiness", they really mean it. and i can really feel/appreciate it. it's extremely fun to use and to see real progress without having to rack my brain and figure out some internals before i can proceed every so many hours. i'm just getting shit done and things work just how you'd intuitively think they should. rails ftw
Some of the design decisions of Flask just don't seem logical, such as using the db instance when defining model parent classes. Makes for strange contortions when defining multiple model files to prevent circular references or db not found errors.
db = SQLAlchemy(app)
class User(db.Model):
...I’ve used it off and on since 2010 (as Pylons) and have been happy with it.
Some more links for anyone interested:
Not really global variables. I would analogize it to dynamic variables from Lisp, which are a feature I wish every language had. I strongly disagree it's a hack or gets in the way. Having access to the request from anywhere without explicitly passing it around is really useful.
Er, no. Their value depends on where in the callstack you read it, not on where/how they're imported. They're like global variables but with thread locality, and with a stack of values.
https://github.com/encode/apistar
Uses Python3 type annotations to do serialization. Not sure it's ready for production, but it has some very interesting new concepts.
Also worth mentioning Sanic which is fast and I believe dispenses with Flask warts like the thread-local Request object (though it does bill itself as "Flask-like").
Flask is still one of the most approachable frameworks I've used. It's great for getting something hacked out really quickly, but for asynchronous requests Tornado is where it's at.
That being said, when I really want performance I usually reach for Golang.
But Flask wins hands down on the richness of its ecosystem.
For me: Python if there's a specific library I want to use, I'm just hacking out a proof of concept, or I'm working with text.
Golang for higher performance, concurrency, stream processing, and cryptography (it has good libraries for that kind of stuff).
But you can always use the underlying library (http://werkzeug.pocoo.org/), which does send everything through a function. Or just implement WSGI directly.
It would be much cleaner to just define a handler type with the signature: `def handler(r: http.Request) -> http.Response`. Those handlers could be passed to routers (which themselves could be handlers), for example (not tested):
class Route(typing.NamedTuple):
path: typing.re.Pattern
method: str
handler: http.Handler
class Router:
def __init__(self, routes: typing.List[Route]) -> None:
self.routes = routes
def serve_http(self, r: http.Request) -> http.Response:
"""serve_http implements the http.Handler interface"""
for route in self.routes:
if route.path.matches(r.path):
return route.handler(r)
return http.NotFound("404 NOT FOUND")
Note that since handlers are just functions, they can also be methods with object-level state. They needn't depend on global state at all, for example, notice how the following routes don't depend on the connection pool (or the request state) to be global: class Server(typing.NamedTuple):
db: DBConnPool
def first_route(self, r: http.Request) -> http.Response:
"""first_route uses shared `db` resource."""
pass
def second_route(self, r: http.Request) -> http.Response:
"""second_route uses shared `db` resource too!"""
passI've used Flask in one other instance, and it wasn't too bad, but I missed CherryPy through the process (cleaner looking code, and obviously more familiarity for me) but I was participating at a Hackathon so maybe my experience is a little shifted. Though I never picked Flask due to never liking how it looked from even just the Hello World I was not a fan of how it's written, but that is just me coming from other languages and looking at frameworks like Sinatra (though I don't do any Ruby it was pretty clean) and Nancy (C#).
raise werkzeug.exceptions.NotFound
instead of abort(404)But you can go from 0-59 with ease and easily translatable templates, etc.
With that said good to see Flask get to 1.0. Long time coming.