Why Django Sucks
speakerdeck.com
speakerdeck.com
Solution: Use something that has no features.
I'm not sure myself how sarcastic I'm being, to be honest. There's some truth in there too (or I wouldn't have posted this). But of course your microframework doesn't have any dependency issues. Rip all those things out of Django and it wouldn't have any dependencies either. Put them all into Flask and it will inevitably have to choose between either having the same problem, or leaving vast swathes of functionality on the table because of the refusal to let the components work together so they stay separate.
Each of those arrows from slide 25 on should have a little label: "Things that you have to write yourself in Flask."
In a way, frameworks are inherently stupid, but who's to decide where between assembly language and x layer abstraction people should work in?
I think people who criticize Django have yet to make up their minds about what a framework is all about, and what, if anything, it's for. They just hold on to their utopian idea of what their framework should be.
Django was created for practical purposes by people who used it in publishing. I think that's a great foundation for a framework - for some people - and piling on it is just a stupid bandwagon.
---
EDIT: I found a better way to put this: the author doesn't have a problem with Django; he has a problem with the concept of frameworks.
It's frankly an awkward fit for loads of web applications. It seems to me (note: Django guy, not RoR guy) that the Rails stuff has adapted much better to applications that fall well outside of the blog/publishing sphere... but maybe that's a false impression.
I'm currently writing a control panel for libvirt and it's a pleasure to use Django, so many features mean I can concentrate on the problem at hand and not on reinventing the wheel.
But it can be very difficult to do relatively simple things with Django sometimes, mostly in the admin pages. Admittedly, this is a pain point people bring on themselves by trying to do too much there, but it's a big red swollen example of how too much interleaving and complexity make it painful or impossible to reason about what's happening.
That said, I also chose to implement many of my admin changes at a higher level: templates which use jQuery, etc. and interact with the REST API for e.g. complex object creation are much easier than the crazy form / widget hacks I used to try.
It's just not constructive for the discussion, interesting as it may be.
I'd say it's more of a problem with frameworks as they exist today. I'd like to see a movement to REST API service frameworks with some level of cooperation to get compatibility for standard client libraries.
Everything then gets built around services: from static site generation to single-page apps, third-party developer APIs to admin interfaces. Then you'd have flexibility to replace any piece of the architecture, whether to get better to performance from a service or to use the latest JS single-page app framework.
https://plus.google.com/112678702228711889851/posts/eVeouesv...
His Big Mandate went something along these lines:
1) All teams will henceforth expose their data and functionality through service interfaces.
2) Teams must communicate with each other through these interfaces.
3) There will be no other form of interprocess communication allowed: no direct linking, no direct reads of another team's data store, no shared-memory model, no back-doors whatsoever. The only communication allowed is via service interface calls over the network.
4) It doesn't matter what technology they use. HTTP, Corba, Pubsub, custom protocols -- doesn't matter. Bezos doesn't care.
5) All service interfaces, without exception, must be designed from the ground up to be externalizable. That is to say, the team must plan and design to be able to expose the interface to developers in the outside world. No exceptions.
6) Anyone who doesn't do this will be fired.
7) Thank you; have a nice day!
Now it has meant that Amazon can transition internal infrastructure into external AWS infrastructure and charge for it.
It really is genius and wouldn't surprise me if this becomes the future of how enterprise companies develop software.
* Form * HttpResponse * All middleware * Template * Etc, it's all classes except if you write function based views
No, they have a different idea of what a framework should do or not do. Doesn't mean they have some utopian idea just because it's not Django.
Django is badass for what it is intended to do: be a kitchen sink. Flask is badass for what it is intended to do: be a platform for composable applications. If you ever need to reason about the internals of your web framework, you want the latter. If you don't, the former is great.
This was a presentation for a room filled with Django developers that likely use it for just about everything.
The purpose of the talk isn't to bash Django, it was to introduce Django developers to some interesting concepts that are worth exploring and a tool that may suit their needs.
I'm not sure what that even means, but I suspect the thing that disproves it is "The last website I built was in Yesod.". And while it may be in some sense targeted to fill the Django space, at the present time (and certainly at the time I worked in it) it was more like Flask and a couple of things lightly tacked on.
No, my main point is that Django is what Django is, and while that may not be perfect, it isn't useless, it doesn't "suck", it just doesn't meet all needs any more than anything else does. Flask doesn't meet all needs either. Don't complain that water is tasteless when what you wanted was mustard. Being tasteless doesn't make the water suck, it just makes it water. Complaining about its watery nature is just silly.
If Django actually sucked I'd probably not have said anything, but it's more successful at actually bringing together all those things than most of its competition. (Though since there are roughly 1000 web frameworks out there I'm sure there's better things somewhere.)
"You sound institutionalized."
I'm not sure what that even means
mattdeboard is referring to Red's dialogue from The Shawshank Redemption: http://www.youtube.com/watch?v=TsiFanovOSIIn practice, I think large frameworks are eventually pretty terrible. It's too easy to compromise your business needs in small ways because the framework offers you something close-enough. Whether those compromises come in the form of over-coupling (which they always do with these frameworks), or in other ways like compromised URL design, query performance, or authorization plumbing.
Great at first, but in my experience a project run long enough in one of these ecosystems tends to outgrow it.
Being faced from the beginning with more of a blank sheet of paper and open ecosystem of solutions to choose from (or build) tends to make you more aware of the trade-offs, and how well the solution you're implementing fits your business needs. Costs more up front, but you're less likely to grow a hate-tumor during years 3-6.
At this point I'd prefer to work on a well-managed, professionally coded project written in PHP than one written using <insert-python-framework-du-jour-here> run by idiot managers.
My own observation is that bad codebases are the result of bad development practices regardless of framework. In my last job the code quality was so poor (and the management processes so broken) that whether they'd used Django, Flask or roll-your-own would not have made a whit of difference.
Case in point: OpenERP. Serious business software doing serious business things, so of course they can't use any of those other toy ORMs, they have to spend 5000 lines of code writing their own: http://bazaar.launchpad.net/~openerp/openobject-server/trunk...
Hey, it might not be so great, but at least they have tests for all of that code: http://bazaar.launchpad.net/~openerp/openobject-server/trunk...
Er...
I know of other projects in a similar state, but they're smaller teams or solo coders, so I don't know that they're quite as fair game for finger pointing...
If you think you can do this better than the Django community, this can work out well but I'd say more often than not when I've heard about it people weren't actually able to spend enough time on this as they'd hoped and keep falling further and further behind Django and other frameworks.
I'm not sure where you work, but this is my experience from using 'wysiwyg' clipper & dbase software in the 80s to Delphi frameworks in the 90s to web frameworks. People think they are very different from the start and then (usually after a management change) they notice the same stuff happens everywhere.
With regards to frameworks. I find it hard to believe that none of them would work out in the long run. I wonder if you are under-estimating the cost involved from the developers to replace or create these frameworks from scratch. This also seems like a selection problem more than an inability of frameworks to meet any development need. I mean they do exist for a reason.
That said, most software products are pretty horrible. Many frameworks are equally bad. Does this mean you should custom build everything? Of course not, you company is not going to be able to afford the time it takes you to write your own ORM, your own web framework, your own logging library, etc... It is your job to make compromises that will allow your company to achieve its goals.
It actually is what Flask does.
1) Project starts out relatively agnostic and casts a very wide net
2) Features start to mature and while you are servicing one use case, you are somewhat unknowingly making your product unsuited to certain different future use cases that may or may not arise.
Thats just how design decisions work. Django has made design decisions to cater to a certain set of needs and they have obviously been quite successful. I don't even use Django but I can tell it doesn't "suck" just by how many people have told me it has fit their use cases quite well.
I actually wouldn't be surprised if X years down the road Flask becomes much less agnostic as its community consolidates and matures.
In Rails, you can rip out ActiveRecord and replace it by an entirely different ORM like DataMapper. There is no real default authentication support, but you can easily plug it in. The list goes on and on: they've done a decent job (I would say 'great', but there are still some improvements needed to make it 'great') at decoupling the various components of Rails and making it easy for users to mix and match.
You need a dependency to offer a certain feature, but not necessarily the default dependency. They have internal API's that decouple the lot. That is exactly what this presentation argues Django doesn't have, but should have.
Now I don't know anything about Django, so I can't judge whether the argument has a factual basis. If you tell me it is wrong, because you can easily replace the persistence or authentication layer of Django, then I have no choice but to believe you. However, the argument is logically consistent and the viability of the alternative it proposes is backed up by plenty of real world examples.
Don't take my word for it, all of this is actually written in multiple places in the docs, tutorials and/or Django site, I can't remember. Here's an excerpt that exemplifies Django's philosophy (from [0]):
> Each view is responsible for doing one of two things: Returning an HttpResponse object containing the content for the requested page, or raising an exception such as Http404. The rest is up to you.
> Your view can read records from a database, or not. It can use a template system such as Django's -- or a third-party Python template system -- or not. It can generate a PDF file, output XML, create a ZIP file on the fly, anything you want, using whatever Python libraries you want.
> All Django wants is that HttpResponse. Or an exception.
> Because it's convenient, let's use Django's own database API, which we covered in Tutorial 1.
Indeed, Django components are incredibly convenient to use, and readily included, and officially supported. But they're completely optional.
[0] https://docs.djangoproject.com/en/1.4/intro/tutorial03/#writ...)
I think you missed the point. In Rails, ActiveSupport does a whole lot of automatic magic with ActiveRecord. But it is not limited to ActiveRecord, as most of that functionality is factored out into ActiveModel - implement those interfaces and your link helpers and whatnot will happily support nonAR models. I use this quite often to represent things that doesn't reside in a database.
Well, most of the time. There are a few things out there that are not migrated to ActiveModel yet that really should be (the model side of datehelpers in forms comes to mind).
As for the comparison with Rails, faking models is the same in Django, as both leverage duck-typing features of their underlying language. In Django, a model is just a class, and many things are just queried via introspection. Many parts just query model_instance.pk. Additionally populating Model.meta and you even get yourself some deeper model introspection features. To me the true important part of ActiveRecord, ActiveModel and ActiveSupport is rather that you have a set of modules that you can readily include/extend into your fake models to inject complete model behavior, and that is something Django lacks.
You name the example of link helpers, and interestingly this is an example of the difference of philosophy between Rails and Django (see [0]). Django parts are coupled more loosely than Rails parts, a possible rationale being that creating coupling between two distant parts such as URLs and models could enforce constraints on each, thus reducing their potential to independently shine and coercing possible alternatives of each to the provided model. Another example: with Django you explicitly create a request object (whether directly constructed or encapsulated into a helper method) to be returned by the view function while Rails does magic for you in the controller.
Interestingly you bring the problem of forms and this is again an area where Rails and Django differ. Rails wants both form and data to be handled by a single model, whereas Django separates form models and data models. The rationale here is that they are two different problems and that they ought to be solved by two different components (yet they share a great deal of similarity, and code).
FWIW I worked extensively with both (although my current job is in a Ruby shop, I worked with Django at my previous job and since I'm more of a Python guy I keep myself up to date on that front too), and am in no way saying that one is better than the other. Choose what works for you.
[0] http://stackoverflow.com/questions/61451/does-django-have-ht...
I think this is incorrect. You can't offer features without implementations; The feature will never be completely agnostic of its implementation. When you get a really strong shift in the possible implementations (for example: websockets or even long polling, vs rpc) then the feature (for example: dynamic UI), if re-implemented, starts exposing very different semantics and secondary features.
To sum it up: if you implement a thousand ORMs based on SQL db's then they're all going to look the same, implement one thing based on a NoSQL database and you suddenly see how the "feature" of "storing data" suddenly becomes something different from what could be anticipated by the people who designed the original "feature" back in the SQL era.
Let's not lie to ourselves and pretend that features are some wondrous thing poised in thin air above their implementations.
I won't slam Django, Django is good. Its most salient traits are its mindshare, liberality with features, big plugin ecosystem. And these traits were not all present from the beginning, when it was the Django developers who were reinventing wheels and going without features. Django's top traits are historically contingent. So in an alternate history, we might be talking about CherryPy having basically the same problems, because of the inherent pain of taking on so many features so quickly, then maintaining backward compatibility, etc.
Good framework or library code takes significantly longer to develop than similar functionality inside an app. When you add goals like trying to reduce boilerplate and coupling, it gets much harder and slower. It is totally valid to question why not just charge ahead with something easier to develop and get done more quickly. There is a real issue to think about here, it's not so clear cut.
It isn't as simple as saying "Flask is only nice because it has no features, anything with features is necessarily ugly." Both features and clean design take time and if you want both, even more time. But design is hard while features earn mindshare and dollars... if they work reliably, then who is complaining?
Now, at this point, Flask actually has a significant mindshare and plugin ecosystem of its own, so it is really inaccurate to say it has no features. And actually Flask does have a number of dependencies as well, with much of its implementation tucked away in Werkzeug (which is hardly a simple library).
You don't have to reinvent the wheel.
That is the fundamental problem of all micro-frameworks. They are so small they are incomplete. You may not like Django auth, but Flask has NO AUTH. You have to go get a third party auth system, or write your own. That means with Django I can get a site, with auth, up in just a few minutes. With Flask, you have to write a login page for the 1000th time in your life. It may be very simple to do that, but it's even simpler to do nothing at all.
Its really not that bad or hard to do at all.
I'm also finding it hard to think of a use case where you need to authenticate 100 users at once, so your initial rationale (100 separate updates) doesn't really work. Surely you'd use a different tool to populate your database, but Django's ORM for day to day stuff?
I'd say that's better than anything hardcoded to a fixed database schema. There's a whole world of development that has no interest in using a mediocre, off the shelf database schema in lieu of one that is designed exactly for the problem at hand.
I guess the idea is that Pyramid exposes a lot of the internals so that you can tweak it, but what's going on in that code is completely lost in the noise. From all of the hits that I can see on Stack Overflow, I'm not the only one who finds it hard to understand.
Not to mention that it completely punts on adding any sort of persistence for user models or password hashing. I stopped trying to figure out what was going on when I realised that
headers = remember(request, login)
actually returns the raw headers as a list of strings, and you need to feed them manually back into the response.Compare to Django's login, which is a lot clearer, even though it includes all of the things that the Pyramid version skips over: https://docs.djangoproject.com/en/dev/topics/auth/#django.co...
The most relevant line to take away from their post mortem is this: "Unfortunately, when designing a framework, you get exactly one shot at creating "the right" API. In this case, we didn't."
So even with a decoupled API, if the design doesn't fit your needs or is too cumbersome to use, you will still need to find a third party solution or hack the core code. Both of which, as mentioned by others, are possible in Django.
This whole thing is about where you're coming from and what software development traditions you subscribe to. We know full well django isn't going anywhere and you can rebut all you want, the alternatives aren't going away either.
Complexity breeds bugs like rabbits; if you can't look at something and understand what's going on (potentially drilling down into an abstraction or two), then it's going to be a maintenance nightmare.
If you can come up with something that's easy to use and powerful, like the declarative_base stuff in SQLAlchemy over the top of the Mapper/Relationship, then I'm all ears - but if complexity is the price that I have to pay for that then it's not an easy tradeoff to make, and in a lot of cases you're better off with the easier, worser solution.
A quick question: do you have any idea of how much work it would take to port SQLAlchemy to Django properly? ie. so that all of the fancy Django manage commands work. I'm assuming a fair bit, but it might be a good way to get some sort of help as far as SQLAlchemy goes. Or you might be happy to continue forging ahead solo, I don't know. Just a thought ;)
There is a version of this I have in mind that would take at least 6-8 weeks of pretty solid developer time. A new layer would be built on top of SQLAlchemy ORM that would look just like Django mappings/QuerySet. The mappings wouldn't be too difficult, QuerySet maybe a little more.
The advantage to that approach would be that existing Django mappings and QuerySet code could be reused in the context of a SQLAlchemy session conversation, that is, the unit of work/identity map paradigms would be brought in. A lot of the "bolted-on/doesnt-really-work" code I see to approximate these features in a tool like JohnnyCache wouldn't be needed anymore.
I'm not sure that this really encompasses "manage" though, I'd have to increase my familiarity with that tool to know everything it does.
Django's auth system requires a backend to implement an API consisting of exactly two methods. One method is passed a set of credentials and returns something "User-ish" (i.e., possessing the attributes of a Django User object), the other is passed an ID and returns a "User-ish" object corresponding to that ID.
Neither of those methods requires the use of Django's ORM, or the use of a database, or really the use of any way to store data at all.
This means that how the backend stores data, and whether it stores data, is irrelevant; if you want to use a DB and SQLAlchemy to interact with it, you can and the auth system neither knows nor cares. You could, assuming a migration plan in place, switch away from the DB and away from SQLAlchemy and store user data in flat files if for some reason you really wanted to, and the auth system would not care and would not notice anything had changed.
I fail to see how anything would be gained by somehow forcing a store-agnostic data API into this picture as part of the auth system, when the auth system currently doesn't even care whether you're storing things.
I'm all for simplicity but some problems have very unfavorable cost/benefit ratios. Auth is one of them.
Talk about solving problems you don't have yet. There may be a very good reason for using a third party anything, but to suggest that this is always the "right thing to do" is ludicrous.
Most of the web frameworks I know tend to do at least two things - the web stuff plus creation and initialization of all other components. This means that the framework is coupled with all of these components and this is the root of all evil in web frameworks. Of course you need a place to do that object creation and wiring work - but it is not really related to web stuff - it should have it's own place in the program, ideally in a Dependency Injection compartment, not necessarily a container based on the available libraries - but it can also be coded by hand (I might change my minde some day but for now I don't see any reasons to use DI container libraries in a dynamic language like Perl). All the arguments about using Dependency Injection apply also here, but even for someone rejecting DI it should be pretty obvious that reading config files and initializing objects is not much related to web stuff and if you buy the single responsibility principle you should split them into separate libraries.
I don't know Django or Rails too deeply - but I've observed this with Catalyst. Now, Catalyst is supposed to be decoupled from the Views or Models and other Plugins, there are many different ones in each category and you can replace them freely in your programs. But Catalyst code-base is still pretty big and then you have all these Catalyst::Models, Catalyst::Views and Catalyst::Plugins that don't really do any meaningful work - they only map one interface into another one. It could be much simpler if Catalyst only cared about the web related processing.
(copied from my blog)
Monoliths also lock you into a certain paradigm. Django locks you into a RDBMS if you want to hook into all of Django's components like auth, admin, etc. And being locked into a paradigm limits the types of problems you can solve and makes it difficult to shift when a new paradigm emerges.
We're in a period of rapid development in datastore technology. If you're locked into a relational database, it makes it difficult to switch and take advantage of these developments. Loosely coupled components like Flask follow in the Unix tradition and free you from these bounds.
Django was well positioned 10 years ago when the RDBMS ruled, but with the proliferation of new DBs and data storage services, it's not well aligned with modern architectures.
...are you out of your mind?
However, for example, Datomic (http://www.infoq.com/presentations/The-Design-of-Datomic) is interesting, which is distributed and uses Amazon's DynamoDB storage service.
Edit: just before my comment gets skewed, my question is: why would you ever use django for a website big enough to warrant this sort of worry? Let's recap: big websites make money which is used to hire coders. Those people are at that point probably porting your website to Agda, or some other cloudscale technology. Sounds like you're the same kind of person who complains that Bash doesn't support OpenMPI and that JavaScript doesn't do fib() well enough and that this here carpentry hammer can't break diamond. Wrong application, dude. Django is for medium-small websites, not for your Cloneddit, Clonebook, CloneSpace, or news.yclonebinator.com; get a different hammer.
Most of my work is with graphs so, for example, if you want to use a graph database to build a social graph with a Bayesian network, you wouldn't use most of Django's components such as auth and admin because they're tied to the ORM -- most of Django would just get in your way. It has nothing to with a Django-based site "outgrowing" auth.
Try to break out of your relational mindset and understand the thread before you decide to go off. And regarding my "paltry 3.79 karma average," you do realize the median for the leaderboard (http://news.ycombinator.com/leaders) is 3.975, right? Again, know what you're talking about.
Of course, the lack of actual motivation in your top post can be explained through being inarticulate as in the paragraph above; it can also be explained by you trying to mesh together a few easy and hip claims. The later motivation could well be something you worked hard to muster up only after initial critique, and given that its connection to the top post hinged on a shaky premise I think that's what has happened here.
Regarding your "paltry 3.79 karma average", the leaderboard is sorted by karma amount, not karma average. There are people on that list who have about 10x as much karma average as you do. And even the guy with the least karma on that list still has over 4x as much karma as you do. Well done computing the median of a biased subset of people. Biased because it selects people with the largest amount of points which easily comes at the expense of post quality. Please read about the bias of controlled, not-randomized studies before you go throwing around statistics you can't interpret. I suggest looking at the tree graph found on page 7 of "Statistics" by Freedman, Pisani, Purves, since you like graphs so much. Coming up with meaningless numbers will only shut up someone troubled by innumeracy, and I am not affected.
The OP/thread is part of an ongoing conversation about the Python community at large and Django's stronghold on the community mindshare because a large portion of development resources goes toward the Django platform rather than to decoupled, external libraries (as noted in the talk).
Most new Python Web developers choose Django as the default option because that's where the mindshare is (hence the repeated "we'll use Django, of course" in the slides), and Django's design and momentum lock the Python community into a certain paradigm, even though new paradigms are emerging.
Kenneth's talk, my comments, and similar comments by people like Mike Bayer (http://news.ycombinator.com/item?id=4079892) were about breaking that stronghold. My example regarding graphs was just an example for you, but my original comment was about the bigger picture.
BTW you were the one throwing around karma average. Have you looked at yours, and are you aware how it's calculated? -- it's not really a good indicator to use when trying to discredit someone.
> The OP/thread is part of an ongoing conversation about the Python community at large and Django's stronghold on the community mindshare
No, it's not. The highest rated top posts for this link talk about complex monolithic code vs flexible code made out of bits which is however lacking in features. This includes the post you're trying to defend using this detraction strategy. The question of Django having or not having mindshare in the python community is secondary to this, and isn't even a topic of the largest minority of comments I've seen on this link.
To support your claim that it's all about community you come up with a short post that is several levels deep, and purport that the original talk bemoans the fact that Django is domineering the community. The talk barely mentions that Django is just a popular choice, it is your completely disconnected analysis that he was complaining about Django's harvesting of the "python mindshare". In fact it mentions Django because according to the talker it's just the top competitor to what he's selling. This is standard course of action when you're presenting a new contender in a space and has nothing to do with "the state of the python community".
In the same way as you try to paint over the past repeatedly changing what you've meant with the original post, you do the same with the side discussion of karma. If it were really as unimportant as you say, why were you defending it in a post just above? You lack consistency.
Yes, I have looked at my karma average. The same page that displays it will also show you that I barely, if ever, post here, and if you try harder you will find out that I've registered about a year ago to post on my own content after it submitted here. This should in fact display to you that this website is not as important to me as you think it is. It's not that I'm new here - it's just that I'm not, you know, "a part of it". However, your comment was just so disconnected from the discussion, I felt compelled to point it out, and I'm glad I did so, because the resulting trainwreck should give you, and other people here, some fodder for thought - not everyone buys your junk logic. You can see it as a pedestrian bystander jumping in to rescue people from a car crash. Not a member of emergency services per se, but the situation warrants action strongly enough that some bystander felt the need to do something.
Threatening people with your amount of experience, jumping around in the supposed meaning of your point, ad hominem (oh, now my comment means this.. no, it means that and you don't get it because i'm so much better than you.. oh, no, it means something else; oh btw, I've been stalking you, watch out!) don't really form a way to have creative and intellectual discourse with anyone. Glad to stomp that out for you, you may thank me later once you've become accustomed to actually admitting when you had made an error, rather than feeling the need to spin it, pretending it's something else.
In my mind, when I made the original comment to your top post, the fallout looked like this:
(original premise): you say that it's very bad that you have to use an rdb for admin
(baiting answer): yeah, so let's just use (nosql database chosen as an especially ridiculous example)
(your answer): you would need to use a nosql database for admin to do (fringe application)
(my answer): but (fringe application) is not what Django was made for. Wrong tool.
(your answer): ok, here's a better illustration. We truly do need Django to be able to do (some thing which is tied to an rdb), but it's much better done if it were in its stead using (some nosql technology).
This workflow has happened (except for the last part), but it came with a lot of bickering and manipulative speculation, which makes me think that you hadn't even noticed it, much like someone who after getting a speeding ticket attributes it to police depravity and oppression of the common man. Therefore, I decided to point it out. Is it really so difficult to admit when you've shot off on a tangent? I liked the link in your top post, quite a lot in fact, but the comment that followed it was of no or negative value because you have chosen to illustrate with non-examples: concepts that do not support your claim. In addition you did this because you really really like nosql databases and probably feel the need to bash on everything that uses SQL from the angle of it using SQL, and sometimes can't control this need. In this way your nature has really messed up the execution of your intentions. I'd have totally upvoted you had you just made a link and no comment, and probably defended the link adamantly from anyone criticizing it. I'd have loved it even more had you accepted that maybe what you thought wasn't entirely correct. But neither of those two things happened. Instead, you bicker and manipulate, finally resorting to trolling through stalking, hoping that you'll find out my name (it's not Rumpelstiltskin) and somehow shock me or make it more personal. And even worse, you fail at stalking, but while doing that show yourself as a big jerk. And I'm not saying I wasn't being negative, but I'm trying to keep form, whereas you display somewhat of a sleazy, vaguely adversarial, win at all costs quality in your discourse, which shows lacks of consistency. Consistency is the most important thing when conveying information, and without it you end up being viewed as a charlatan. Think about it.
(original premise): you say that it's very bad that you have to use an rdb for admin
...but it's not what I said; this is what I said...
"Django locks you into a RDBMS if you want to hook into all of Django's components like auth, admin, etc"
I'm not saying that it's bad that you have to use a relational database for auth, I'm saying that if you don't use a relational database and the ORM then you lose admin, auth, third-party apps, etc. Strip all of that out and what do you have left? See slide 71 (https://speakerdeck.com/u/kennethreitz/p/flasky-goodness).
And I have said this several times before (http://news.ycombinator.com/item?id=2911275), so no, I am not trying to retrofit my argument.
The talk barely mentions that Django is just a popular choice, it is your completely disconnected analysis that he was complaining about Django's harvesting of the "python mindshare".
If you don't think that's at least the subtext of what the presentation was about, look at the slide for Kenneth's primary thesis: "Open Source Everything" (slide 10 - https://speakerdeck.com/u/kennethreitz/p/flasky-goodness). And then go through the presentation again to see what he means -- "Single Code Bases Are Evil" (slide 45).
BTW, did I mention: "stalker"?
I do not know much about Flask and it looks like it has some bare bones middleware and context processor tools, but it doesn't look like it does much more than what web.py offered, well except for all the testing tools (which look pretty cool).
Sure the article has a good argument about separating components, but before you propose your alternative you should include all of those features (decoupled I suppose) that Django does for you already. In addition the patterns page[1] on the Flask documentation is basically a cookbook for things that Django already does, and by the way encourage the one code base architecture this presentation argued against.
python manage.py syncdb
when you can write a function: from contextlib import closing
def init_db():
with closing(connect_db()) as db:
with app.open_resource('schema.sql') as f:
db.cursor().executescript(f.read())
db.commit()edit: using the current toolchain it's:
alembic upgrade headedit: not if you're using sqlite, since alembic doesn't seem to try too hard supporting it.
Start reimplementing^Wrecomposing Django on top of their lightweight framework.
Because its brand new, written by pretty much one person (I'll give you a hint, it's me), and also sqlite barely supports migrations itself (http://sqlite.org/faq.html#q11). You're trolling pretty hard in this thread, maybe you should let other toolsets besides django have a chance.
I'm sure your code is fine, but you can't possibly argue that it is on par with a major component of a major framework and be taken seriously.
Which is fair enough IMO, but it's not really convincing me that Flask is a better way to go.
https://speakerdeck.com/u/alex/p/why-i-hate-the-django-orm
Yet the developmental resources SQLAlchemy and Alembic are a tiny fraction of what Django has. It's the tremendous gravitational pull of Django and the habits of its community writing things hardcoded to Django that suck the life out of other projects in the Python community.
And yes, I know you wrote it. You wrote SQLAlchemy too.
- Error handling: Django error page is great, unless of course it's a AJAX request. Pylons does this in a much smarter way
- Django ORM is awful. Easy to use yes, but awful
- Django Auth is a "good intention" but awful implementation
- Django templates are sloooooow. Jinja 2 is an order of magnitude faster
Amongst other warts
Also, the author apparently found the hard way: don't use Django as an api server
I may sound critical of Django, but I think it's a "complex framework for simple usages", I mean, if you need low flexibility go for it, you'll do what you want really quickly.
There is an entire class of problems (mainly enterprise-related) for which the simplicity (ORM / Auth / etc..) is great. I managed to tie Django Auth into Active Directory which made the user's experience (relatively) seamless, as opposed to the previous reality (everyone with a different password for different applications).
Can't you also use Jinja templates in Django?
I'm not convinced that I would use Django on a large project where I get to cooperate with 15-20 other programmers, but if the scenario is 3 people with relatively normal business requirements it makes a lot of sense.
YMMV.
You can certainly use Jinja2 templates on Django, for most uses Django templates are ok
You also can't use templatetags from reusable apps (or Django itself) but it's easy enough to write a wrapper for those that allows you to.
We switched to Jinja2 for Canvas because the Django templates were atrociously slow, and it was absolutely the right decision for us.
Put another way: I inherited a site where someone noticed that a view was slow and switched everything to Jinja2 for magic pixie dust speed ups. This made almost no difference but did complicate maintenance and require reinventing common Django template tags and filters. I joined the project later and actually made the page much (50x) faster by actually profiling and not executing 8,000 SQL queries.
Jinja2 is a great project but I have yet to run into a case where the Django/Jinja debate in any way affected performance significantly. Pick the one which causes you the least support grief and worry about problems you've actually measured.
I can assure my assertions are based by a lot of benchmarking of a Django project that heavily depended on the ORM. And it's not even about the quality of the queries, Postgres was eating them like hot cakes, but the ammount of queries itself was making it slow. Even for things like user_token.delete() (this was an open source project in Django that we were adapting)
Oh sure, I don't recommend the first step of optimization to be switching to Jinja2, Django templates are fine for 99% of cases. But in my case, Django templates were being used in a very specific way (which btw was done in the original project, that is, not by me) which was very slow (think 1s per page, and that's without querying the db!)
Similarly, 1s to render a template sounds rather unusual - if that's not just something like not using the cached loader on a slow filesystem it's screaming for logic to move into the view or a template tag.
I will also note in both cases these started out as general assertions which were then qualified to refer to specific edge cases. Again, without describing the exact code being benchmarked it's a disservice to through out performance advice to people who might take it as a general rule rather than understanding that it's unlikely to be a significant problem for most users.
In Python there aren't many queries! That's the issue!
Let me explain better. Django ORM is converting a few lines (and sometimes ONE - like user_token.delete() ) of python to tens of queries. These tens of queries take around 200ms (or more) because each query takes around 3ms/10ms
user_token.delete() was taking 300ms (I wish I was kidding)
"Similarly, 1s to render a template sounds rather unusual - if that's not just something like not using the cached loader on a slow filesystem it's screaming for logic to move into the view or a template tag."
No, not cached loader, not slow filesystem. It's a for with an inner include.
https://docs.djangoproject.com/en/dev/ref/models/querysets/#...
“No, not cached loader, not slow filesystem. It's a for with an inner include.”
With a lot of loops - again, not common for most web apps (who wants a 5mb HTML page?). You should be able to avoid this by using a custom template tag to load once and render many times.
If you rely on model inheritance, or your models have lots of relationships, Django uses the DB really inneficiently
Like, making lots of queries (mostly repeating itself), so a simple thing takes a lot of time.
It's a little bit difficult to explain (you can imagine it was more or less difficult to figure this out as well)
Django auth was designed around the typical use case ca. 2005. The world's moved on a bit since then.
What I end up doing nowadays is roll my own (and re-use bits of contrib.auth where appropriate, such as password hashing) using a custom auth backend and keep a separate site for the Django admin which uses contrib.auth models. As long as I don't have to use 3rd party apps that rely on auth.User I'm fine.
This is how I've gotten around the user name length limitation. I have a longer field in the subclass, and implement a backend to check that. But because it's a subclass, foreign-key relations still work.
For example, my typical use case: unique email address for logins, no usernames:
I suppose you could subclass User with a longer username, and sync the username with the email address using a signal, for example.
Still, it's a chunk of workaround I end up doing one way or another with each new project. Hopefully soon (based on discussions on django-developers group) we'll see some kind of pluggable User model.
Template execution speed is unlikely to be the bottleneck for the vast majority of sites. I prefer Jinja2 for the flexibility (macros etc) rather than the performance.
That is a fatigued point. I use Linux and store the few tweak I have to do manually in a install_note file. Next time I want a fresh install I just follow the doc and in 10 mn I have a fully adapted environment. Then I do not tweak anything more at this level. All subsequent tweaks are vimrc and bashrc modifications that are pushed to bitbucket, and I guess I would do those on MacOS anyway.
Being able to fiddle the config do not mean you have to, and the days are gone when Linux was not that stable.
The thing I actually spend a lot of time tweaking for the few days I have a new device or OS version is my phone (Android). On these little big guys I get back the tweaking excitment I got with my first PCs (Oh! Look, you can change the prompt! Look, you can move the start bar to the top!)
I think what is actually interesting with mobile phone is that they are not stabilized, a lot has to be invented for them, and each new OS version or even some apps really add new possibilities.
But for Linux, Windows or Mac, no new exciting thing is in sight, and spending too much time tweaking the config just mean you have time to spare.
Of course I'm kidding because these are valid critiques. Django's code base has a bad case of introducing really hard to debug interactions. But, to be fair, those are fairly rare.
However, as a Django lover I must say that Flask is missing a lot of what I love about Django: sane pre-built options for getting you to 90% functionality quickly. That last 10% can be difficult, but that is better than a more difficult 90%.
One thing that is rather annoying with Django is the learning curve (there's a lot in there), but the docs are so good that it isn't that bad (and one could argue that Flask is harder to learn because it means learning SQLAlchemy, Werkzueg, etc... too).
As he mentions in the slide, best tool for the job. Flask is certainly more Pythonic (IMO) and beats Django very handily for simple apps, but the ability to skip reinventing the wheel will keep a lot of people in the Django camp for the foreseeable future.
[1] http://3rdaverad.io/shows/django-podcast/episodes/deployment...
From my experience, the problems arise when you begin bending it to fit your particular use case. For instance: Django is naive regarding multi-tenancy, something you usually need when building web apps, so you'll have to hack some parts in it; the coupling of most 3rd party apps with the built-in authentication app can also get in the way; etc. If your use case deviates too much from the "website" model, using Flask (or just going down to WSGI) for the plumbing and then picking best-of-breed libraries (SQLAlchemy, Jinja, etc.) can pay off in the long run as opposed to going with monolithic Django from the start because, down the line, you'll find you had to hack most parts anyway.
Just for one example: stepping through an IDE's debugger, integrated into the code editor, to track down a problem is incredibly handy. It's a habit I picked up while living in Eclipse doing Java work, and why most of my Rails work is now in RubyMine instead of Emacs like it was when I was in school.
And sure, if I had unlimited resources, and wasn't annoyed at all by having to carry around a bunch of primes, and could change lenses in an instant (or was carrying four different bodies too), I'd rather have a set of excellent primes than a zoom.
Very much like how I'd love to be able to integrate (and possibly write myself) a bunch of services to perfectly fit my problem instead of using a framework. But it just isn't very practical for a lot of areas. And then the problem changes, and the purpose-built solution to be adapted... and then this happens a few more time and how perfectly have you maintained your original separations of concerns?
Command line interfaces are cool especially for stuff you do all the time
Counting Flask v0.8 with cloc yields twice that:
$ perl cloc-1.56.pl flask --exclude-dir=testsuite,ext
18 text files.
18 unique files.
114 files ignored.
http://cloc.sourceforge.net v 1.56 T=0.5 s (36.0 files/s, 8008.0 lines/s)
-------------------------------------------------------------------------------
Language files blank comment code
-------------------------------------------------------------------------------
Python 18 694 1748 1562
-------------------------------------------------------------------------------
SUM: 18 694 1748 1562
-------------------------------------------------------------------------------
And that doesn't include the size of Werkzeug, without which Flask cannot run: $ perl cloc-1.56.pl werkzeug --exclude-dir=testsuite,ext,debug,contrib
20 text files.
20 unique files.
126 files ignored.
http://cloc.sourceforge.net v 1.56 T=1.0 s (20.0 files/s, 13460.0 lines/s)
-------------------------------------------------------------------------------
Language files blank comment code
-------------------------------------------------------------------------------
Python 20 2307 4277 6876
-------------------------------------------------------------------------------
SUM: 20 2307 4277 6876
-------------------------------------------------------------------------------
Including the contrib and debug packages of Werkzeug adds another 3000 LOC.It's called "spin". It's common practice for people trying to sell you on something.
In my few years of developing in Django I have had my frustrations and joys, many of the frustrations coming from the idea that I should do things how the framework wants me to, only to realize that it is still python that I'm writing code in. The idea of Django is not to be some utopian framework where all of your pythonic dreams come true, it is to enable you to build applications quickly and with ease.
While Django may have been created to be a publishing platform, our primary use for it is a genetic analysis application, which is complicated enough without having to worry about the framework, and trust me, Django is not anywhere near a problem in the app. We also use Django for a separate report delivery system, which has API endpoints and is constantly being fed data from 3 other applications, and again, Django has never been an issue.
Sure, you can roll your own libraries with something small like Flask, and reinvent the wheel many times over, but do you actually get features rolled out? Or are you constantly patting yourself on the back for keeping such a small codebase while maintaining a home-grown system and hoping you can get a feature out the door while fixing all of the bugs that not only the system may have introduced, but your features as well.
Here are my biggest worries of a very customized/home grown framework: 1) Does the knowledge of the framework transfer to the next project you work on? 2) Are you writing documentation so that the next person can understand the code? If so whats the time cost for that? 3) Are you spending more time building the perfect system or rolling out features?
Don't get me wrong though, I love working with small polished libraries and connecting them together, namely in node.js, but it is entertaining more than productive.
I believe that monolithic framework are aged too. Django and also Rails as monolithic as they are force you into given patterns, even if you can choose specific modules. I made my first experiences with a highly modular micro framework (Node with Express) some weeks ago and I have to say that I don't want to go back. Even if it seems that you have to reinvent the wheel sometimes (but in reality you don't) your application reflects your use case much better, it's more fun and you are again programming yourself—deciding on architecture, structure and design patterns.
I know this for a fact because upgrading a massive django deployment from 1.1 to 1.4 was a huge project for us.
That said, I still love all the out of box defaults that django provides and the fact that extending them is relatively painless as long as you spent a few years learning the ins and outs of the system ;)
Clearly, there are building blocks that are useful across most applications. You can gather those into libraries and reuse them over time. But, frameworks...no, there are no silver bullets, no fat-free fat, no sugar-free sugar, etc.
Rails 2->3 tried to the general route you're talking about (but still with language API connections, not REST. That would be even harder in some ways) --- with, well, mixed success. And Rails starts out lower level (much less UI built-ins) than django, another thing that would make it even harder.
I've had many failures in personal homegrown projects. :)
Abstraction is hard. To do super high level of architecture abstraction _well_ takes experience and skill, as well as more developer resources. It's easy to go off into architecture astronaut adventures, and you end up spending all your development time trying to keep the parts working together, significantly sapping resources to actually, you know, provide new functionality.
That said, there is certainly such a thing also as too little abstraction and too much tight-coupling too, obviously. There is a happy medium.
I understand that "why django sucks" is a better, more provocative title that will get read more than "why django isn't perfect in every way and i prefer using flask for this", so i don't fault the author for choosing that subtext.
However, the general "tradition" (yes, its a tradition now) of justifying a tech/infrastructure decision with "Ah! language/framework/db made popular by others is a horribly broken mistake! you are doing it wrong!" is 1. getting old, 2. counterproductive for engineers.
They are tools. There are different tasks with different requirements. They have different pros and cons and different learning curves. Some tools are better suited for some tasks. Some tools are even better suited for most tasks. Sometimes it even makes reasonable sense to use a product that isn't the best of the best of the best if you are really certain you don't care about the dimension in which your tool is not the most amazing.
Hammers are bad for cooking eggs. Spatulas are bad for nailing nails. I made eggs this morning. Keep an eye out for my upcoming blog post: "Why hammers suck!!"
On the other hand, in the world of frameworks, it's not entirely common for the use cases to be (as) disjoint as they are for hammers vs. spatulas. More often, frameworks overlap in functionality and differ on matters of style and ideology. And this is what feeds the flame wars.
For starters, you have a choice between MyKitchen and spatula. MyKitchen has everything you need to make a reasonable pasta meal for up to 8 guests. The pasta practically serves itself... even when you are making steaks. spatula is totally dedicated to scraping things out of pots, and obviously you could just use MyKitchen.SpatulaFactory(_ctx) instead (you did read the equipment manifest, didn't you?) Plus MyKitchen has a plugin which will make pork buns that practically serve themselves... why waste time with low-level stuff like spatulas?
Some guy graduated from spaghetti to pizzas and he can only scoff at spatula, which is not necessary at all, since you can cook pizzas directly on the rack.
Another guy made this incredible pocket-sized leatherman which includes compact versions of all the kitchen tools including a camp stove.
It is true that most frameworks are better suited to some tasks than others, but for a given task one might be just plain technically inferior, or only different in some stylistic way.
Not that style doesn't matter, if it makes you feel happier doing your job. Otherwise, why bother with Ruby or Python when there is already Java EE or COBOL?
flask is great. but if you want the admin, then you have to build it yourself. i've used django formsets ONCE, ever, but when i needed them I'm glad that django had them instead of me having to build them on flask.
then i've used flask for awesome projects that i knew in advance i didn't need that stuff.
different needs, different tools.
If I think a hammer looks nice but someone informed explains that it is designed in such a way that the head will tend to fly off, I find that very instructive. The many broken spatulas on github are also instructive.
If you want a pre-built admin, Django provides for a different need, yeah... but if the needed stuff is in the large overlap between Django and Flask, you can't just say "different needs" because you are considering competition to satisfy the same needs. (For example, Flask is promoted for HTTP APIs, but Django also has some good packages for putting together HTTP APIs, so that it is hardly clear that Flask would always be the better choice for APIs).
Most of the argument (here as in emacs vs. vim) is in matters of taste or philosophy - or a dead heat between valid technical concerns. tastypie or Flask? I submit that it matters more what makes you happy and productive, so that it is entirely valid to choose Flask, or Django, or both. After all, it is your life you are spending on all this, you should be happy. If you hate emacs, there are alternatives.
In the end, as the application grew, I had to throw out most of Django and just use my own custom written code. Steep learning curve for a process that will be thrown out later anyways.
A micro-framework is much better. At least you can mix and match as you want.
I'm quite fond of Python and I like what I have used of Django, but I'd be willing to wager that a lot of other people from PHP land have wanted to use Django and have been put off by how hard it is to set up.
Obviously, I could be doing something wrong, so if it's obvious that I'm doing something wrong please say so.
Unless... the person is a weirdo, like me.
In most cases people are looking to prove some idea and they just want the web framework equivalent of "a car that gets me from point A to point B I don't care how.", Django gets the job done and in that capacity is really nice to use.
Personally I don't like using Django. I like to fiddle. I like to tweak. (I like my string beans quarantined!) I like my systems to work exactly the way I want them to work. I have strong opinions about how things should work and am not usually willing to compromise on fundamental issues.
Django does not (in general) make this easy. I wrote a post a while back about the hoops I had to jump through (and the source I had to spelunk through) just to use form field sets and to modify the error reporting (http://mikepk.com/2010/08/python_django_forms_errors_fieldse...).
The real tipping-point for me in not using Django was the ORM. I think it's great for getting up and running quickly but I tend to be of the "ORM-as-Vietnam-of-software-engineering" camp. It's partially due to my OCD/control-freak need to have maximum control and visibility of the RDBMS. I've been converted to using an ORM by SQLAlchemy, but mainly because the philosophy of that project is not to hide the RDBMS from you but to make it easier and more pythonic to work with.
While Django is theoretically decomposable, you lose the ability to use many of the plugins, apps, etc... the moment you deviate from the standard package / install. That's what the arrows in the slides indicate. If you're willing to get something that nearly approximates the functionality you need, and don't care that's it's not exactly what you want, then Django all the way.
Teh Awesome: * Get up and running very quickly * Lots of batteries included * Great Docs * Limited config hell
The Bad: * Tight coupling of features and third party "apps" * Yes you /could/ customize things but then you lose many of the benefits of why you're using Django in the first place * Customization breaks things * Too-strict templating, almost-python-like-but-not-quite * ORM is of the "vietnam" variety
Django:Ubuntu::Flask:ArchLinux
Django gets you 90% of the way from the start, it's in the tagline: for perfectionists with deadlines. However it's difficult to change certain parts of Django.
Flask gives more control but comes at a cost. Each framework has their uses.
Any suggestions for making it easy to build REST style APIs? Is piston the #1 choice still?
The issue I have with piston is that it didn't turn my objects into JSON automatically for me when I returned from the call. I also had to map each and every call (GET/PUT/POST/DELETE) and there was no default out of box behavior. I felt like I was violating the DRY principle over and over.
Tastypie was great when I started but I wanted to do some non-RESTful things with it. Like POSTing to /article/{id}/{action}. Yes it is not REST...I don't care. It makes a lot of sense to POST to /article/15/publish to publish an article. I had to override so much inside tastypie it was getting to me.
Django restframework is a bit different. Default behavior is centered around mixins (basically multiple inheritance). I created a mixin for actions being specified and basically added it to any resource I wanted to have that. If you want to know more feel free to ask.
That sounds like the perfect place to use a Python function decorator, which lets you wrap a funtion in standard boilerplate.
it's interesting to me that django seems to be getting grief for some of the same things zope was/is. Time to reinvent the wheel again I guess.
http://www.jrandolph.com/blog/2006/02/02/zope-vs-django-here...
So surprise surprise, you stray from the happy path the full stack framework lays out for you, be ready for the pain.
the post goes into why there is room (and a need) for both in the ruby web ecosystem, and where you'd want to use each one.
Titles are High Tower Text (Flask Logo Font): http://www.fontyukle.net/en/High+Tower+Text.ttf
Text is Gaudy Bookletter 1911 (Open Source!): http://www.theleagueofmoveabletype.com/goudy-bookletter-1911
And code examples are Monofur: http://www.dafont.com/monofur.font
Thanks for sharing. The site has a few other interesting presentations by the same speaker.
Also, you might be interested in this video, http://www.youtube.com/watch?v=i6Fr65PFqfk "Why I hate Django" by Cal Henderson then of Flicker. 2008 though - I'd love to know about an update about the things addressed.