Live data from Hacker News

Django plugins you shouldn't start without

blog.hndigest.com

71–80 of 89 posts

Re: Django plugins you shouldn't start without

#71

As someone who is just starting to dive into Django and Python in general I have to admit being confused by benchmark after benchmark that puts Python near to the bottom of the performance curve when compared to other technologies (Go being one that jumps out at me). I have to admit that part of me is wondering if I am making the right decision in investing time, effort and money getting up to speed on Python/Django…

I'm certainly no expert, but thought I'd chime in as I have been wrestling with the same issue. I enjoy web development and have done projects with Java with JSP's, a few smaller projects with Rails, a large Django project, and now am playing with Rails again. Your performance concerns (and I believe the other comments have touched on this) likely don't matter for most real world sites, and then, even if you get big,…

Yes, deployment automation is definitely on the list. I wouldn't think of doing it any other way.

Re: Django plugins you shouldn't start without

#72
post #38
post #33

Maybe I'm delusional, but even as someone who has worked pretty extensively (4 months of full stack Django development) with Django, posts like these things make me want to stay away from Django. I read this post, and I see bandaids. I see bloat, and I see warts. I don't want to build on a codebase that needs 5 extensions out of the box to be sane. Granted, I know this is not the real story with Django. It is a rathe…

If it helps any, as someone who's been building Django sites for years, I will say that while all of those are at least handy, absolutely none of them is needed. On the list, the only one I use with any regularity is South, which I do consider must-have. That said, it seems that the Django core team agrees, as it's being (or maybe is even finished) pulled into Django core.

Totally agree. The title of the submitted most is a bit extreme, these aren't "Django plugins you shouldn't start without" these are "Django plugins that are nice to have". It's false, as the grand parent comment thinks, to presume that django "needs 5 extensions out of the box to be sane".

I've been working with django full time for 3 years and the only one I use is South.

Re: Django plugins you shouldn't start without

#73
post #6

Excellent. Pile up your django with extensions, then look forward to the fun when you have to port your app from e.g. django 1.3 to 1.5 and find a new set of versions of all of your dependencies that work nicely together. And of course figure out a migration path for it all. That is, if extension xyz is still maintained at all. Lean is beautiful, people. Carefully assess every dependency you add, as each one has the…

Wait. If you need a piece of functionality, you either get something that works out of the box, or you spend X hours writing it. If the out-of-the-box thing breaks and you spend Y hours fixing it, then Y has to be much greater than X to not be worth it, which, in my experience, it never is. Not to mention that, if the library broke, then the thing you would have written would have probably broken as well, and you wou…

> If you need a piece of functionality

Depends what you mean by "need". Often when you need a piece of functionality, what you actually "need" is a small subset of what a third party app is wanting to provide, and I've often found simply using out-of-the-box apps for this adds a fairly huge amount of complexity that is just not needed.

My favourite case in point would be adding very simple blog functionality to something - which is fairly quick & trivial in django, but out-of-the-box blog solutions promote themselves with tempting-features-that-you-dont-really-need that inadvertently add a lot of complexity and before you know it you're a few releases down the line and you realize that the author doesn't really know how to use South properly and your db ends up in a slight migration-state-limbo forevermore.

Though note that I am _not_ saying don't use external dependencies - I use several of those listed in the article (I am a big fan of django-reversion) - but remember to look at everything with a critical eye before inclusion.

> This just smells of FUD to me

It's all very well and good saying that but a stack of previous bad experiences doesn't smell like FUD when you're on this end of them.

Re: Django plugins you shouldn't start without

#74
post #48

What, no django-annoying? That's the first thing I ever use: https://github.com/skorokithakis/django-annoying That, and shortuuid: https://pypi.python.org/pypi/shortuuid/ Disclosure: I maintain one and wrote the other, but they and South are the three things I use for every project.

django core here, some feedback on -annoying: It'd be nice if you were clear about what versions of django and python are supported. From django-annoying's feature list: * render_to - seems to be roughly equivalent to django.shortcuts.render * signals decorator - now in core[1] (since 1.3) * ajax_response - seems useful, though might make sense to check request.is_ajax[2] * autostrip - hmm, seems oddly edge case-y, I…

I really like the fact that render_to is a decorator. That cleans up a bit of boilerplate that would normally be in the view (even with django.shortcuts.render).

Re: Django plugins you shouldn't start without

#75
post #68

Earlier quoted context omitted.

> So you're saying that if I don't use multithreading my global variables are not, in fact, global? The request object is context local. If there are multiple concurrent requests, all request have different request objects. I don't know what definition of global variable you have, but this is not it.

> The request object is context local. The request object is a threadlocal (or, if greenlet is installed, a greenlet-local). Which is exactly the same as a global variable in a single-threaded program.

> The request object is a threadlocal (or, if greenlet is installed, a greenlet-local).

request objects aren't stored in python's thread local storage. If they were, a thread re-use will leak context local. Werkzeug uses the thread/greenlet id as key in its storage and cleans up when the request completes.

> Which is exactly the same as a global variable in a single-threaded program.

In a single threaded server, the context locals won't leak from one request to another. If they were global, they would. I don't see how request object has anything to do with global variables.

Re: Django plugins you shouldn't start without

#76
post #66

Why is south not number one in flaming gold letters? Seriously, south should just be part of django at this point and it is insane that there isn't this functionality built in. Is changing your data models after you started development so crazy?

Database migrations are being added to Django core, by the author of South.

Re: Django plugins you shouldn't start without

#77
post #73

Earlier quoted context omitted.

Wait. If you need a piece of functionality, you either get something that works out of the box, or you spend X hours writing it. If the out-of-the-box thing breaks and you spend Y hours fixing it, then Y has to be much greater than X to not be worth it, which, in my experience, it never is. Not to mention that, if the library broke, then the thing you would have written would have probably broken as well, and you wou…

> If you need a piece of functionality Depends what you mean by "need". Often when you need a piece of functionality, what you actually "need" is a small subset of what a third party app is wanting to provide, and I've often found simply using out-of-the-box apps for this adds a fairly huge amount of complexity that is just not needed. My favourite case in point would be adding very simple blog functionality to somet…

Ah, you're right there, if you're talking about a blog app, I agree with you. I had much smaller pieces in mind, such as the packages I mentioned before. Each one of those does one specific thing and does it well. Blogging is pretty much the worst example here because it's highly, highly custom to each person and easy enough to write that you wouldn't bother with a library, which would end up not doing what you want in the long run anyway.

Something like shortuuid, on the other hand, is pretty much a slot-in.

Re: Django plugins you shouldn't start without

#78
post #48

What, no django-annoying? That's the first thing I ever use: https://github.com/skorokithakis/django-annoying That, and shortuuid: https://pypi.python.org/pypi/shortuuid/ Disclosure: I maintain one and wrote the other, but they and South are the three things I use for every project.

django core here, some feedback on -annoying: It'd be nice if you were clear about what versions of django and python are supported. From django-annoying's feature list: * render_to - seems to be roughly equivalent to django.shortcuts.render * signals decorator - now in core[1] (since 1.3) * ajax_response - seems useful, though might make sense to check request.is_ajax[2] * autostrip - hmm, seems oddly edge case-y, I…

Thanks for your feedback, let me reply to it:

As JshWright said, the appeal of render_to is that it's a decorator, it does clean up views by a lot.

The signals decorator is now obsolete, I also find ajax_response very handy (when I'm not using CBVs), autostrip is a bit edge-casey, I agree.

get_object_or_None is pretty much 1.6's .first(), but there was no alternative until 1.6. AutOneToOne/JSON fields are there because of convenience, get_config I have no idea about (I didn't write these), StaticServer, also no idea.

The thing is that this library has been out for years, and most of these things didn't exist in core when it came out, so it was really handy in its time. I've been using it for quite a few years, and that's also why I took up maintenance of it.

In the long run, I'd like to see the things that make sense in it integrated into core, especially the @render decorator.

Re: Django plugins you shouldn't start without

#79
post #39

What, no django-annoying? That's the first thing I ever use: https://github.com/skorokithakis/django-annoying That, and shortuuid: https://pypi.python.org/pypi/shortuuid/ Disclosure: I maintain one and wrote the other, but they and South are the three things I use for every project.

ShortUUID looks like fun. I usually just get a UUID4 and grab the last section of the generated UID. Something like str(uuid.uuid4()).split("-")[4] I'd like to say that I then do a duplicate check, but I don't think I've ever had a collision, so I'm not actually 100% true that I do. Best case, you've saved me a database query, worst case, you've saved me a potentially painful Exception. Danke.

It's pretty unlikely that you'll get a collision if you grab enough digits, but hex is only 16 digits. One easily has 62ish characters available (ShortUUID removes lookalikes so people can still read and type the codes), so why not squeeze as much randomness in them as you can? That's pretty much why I wrote it.

Re: Django plugins you shouldn't start without

#80
post #61

Earlier quoted context omitted.

That's one of the things about Django that I really like and one of the things about Flask that really scares me. I'm writing a retrospective now about things I've learned in almost 5 years of working on Google Search, and the entry I just finished was "In almost every case where we allowed non-local effects, it has bitten us. Badly." The cost is in understandability, and is usually not apparent when the choice to ma…

> "In almost every case where we allowed non-local effects, it has bitten us. Badly." But the request object in flask is not global. If the guarantees break(request locals leak to other requests), it will be a problem. I never have had a request local leak in flask. On the other hand, I have ran into cases where I need the request object in django signals. A simple task of getting the full uri requires either a reque…

Leakage between requests is only one of the problems with globals. There's also poor testability, inability to re-use functions that reference the request internally, inability to statically analyze dependencies (less of an issue in Python, since the lack of types makes it hard to analyze them anyway), additional context that the developer must keep in his head, and inability to cross-reference parameters & call-sites and identify where a given variable is coming from in code browsers or debuggers.

Singletons are no better - if you dress it up as RequestManager.get_current_request(), it's just as bad. If you don't understand why something is a bad idea, complying with the letter of the law without complying with the spirit doesn't really get you much.

I think this is the way in which my programming style has changed the most over the last 10 years. I used to want my programs to do everything and have access to everything. So I'd write PHP scripts that would do "SELECT * FROM table INNER JOIN table2 WHERE ..." and pass around the whole result set to every function and every template in the app in case they wanted to access some data in it. That way, I only had to change the DB schema and the template when requirements changed. (Anyone who's thinking of doing this, you're introducing massive data leakage and security issues into your app.)

Now I want my programs to do as little as possible and have access to as little as possible. Usually I end up pulling out the values I want inside the view function and calling any helpers using only those values, so I don't pass the request around anyway. The actual work of the program happens on strings, or ints, or structs, or other values specific to the domain.

I think what changed, for me, were a few things. One is that I got better at visualizing the operation of a large program as a whole, so instead of thinking "Hmm, I need a request here, how can I get access to one", I started thinking in terms of "This is how data enters the system, this is what we need for each computation it performs, and this is how we combine those results to render a page - how can I change it so the system still hangs together but does what we want now?" Another was that I kept running into instances where I could almost re-use a function, but was blocked because of hidden dependencies that it didn't really need. A third was testability - I learned how crucially important it is to be able to test parts of the system in isolation, and that's really hard when you have to setup the whole system context to run any function. A fourth was that I worked a bunch with both systems and found that adding a parameter to each function along a call path is easy (but tedious - if only there were a refactoring tool to do this for us), while disentangling a tightly-coupled function that depends upon a lot of implicit state is quite challenging.

Post reply on HN