Way back in the early days of Django, it used to magically import certain functions before any views were ever run. At some point that bit of magic got stripped out and now we have to explicitly import the things that we are going to use…much like everything else in Python. One thing that Simon Willison suggested at DjangoCon is that the core developers might think about including a common set of functions that could be imported and used as shortcuts instead of importing everything again and again.
I shrugged it off at the time, thinking it was a solution in search of a problem, but wanting to keep an open mind, I wanted to try it out in one app to see how it would look. In this spirit, I created a file called dj.py inside of a project of mine, django-avatar. I looked around at what some of the most commonly used functions were, and came up with a dj.py file that looked something like this:
fromdjango.contrib.auth.decoratorsimportlogin_requiredfromdjango.templateimportRequestContextfromdjango.shortcutsimportrender_to_responsefromdjango.utils.translationimportugettextas_fromdjango.httpimportHttpResponseRedirectdefdelete(request,extra_context={},next_override=None):avatars=Avatar.objects.filter(user=request.user).order_by('-primary')ifavatars.count()>0:avatar=avatars[0]else:avatar=Nonedelete_avatar_form=DeleteAvatarForm(request.POSTorNone,user=request.user)ifrequest.method=='POST':ifdelete_avatar_form.is_valid():ids=delete_avatar_form.cleaned_data['choices']Avatar.objects.filter(id__in=ids).delete()request.user.message_set.create(message=_("Successfully deleted the requested avatars."))returnHttpResponseRedirect(next_overrideor_get_next(request))returnrender_to_response('avatar/confirm_delete.html',extra_context,context_instance=RequestContext(request,{'avatar':avatar,'avatars':avatars,'delete_avatar_form':delete_avatar_form,'next':next_overrideor_get_next(request),}))change=login_required(change)
And here’s what the code looked like afterward:
12345678910111213141516171819202122232425262728
fromavatarimportdjdefdelete(request,extra_context={},next_override=None):avatars=Avatar.objects.filter(user=request.user).order_by('-primary')ifavatars.count()>0:avatar=avatars[0]else:avatar=Nonedelete_avatar_form=DeleteAvatarForm(request.POSTorNone,user=request.user)ifrequest.method=='POST':ifdelete_avatar_form.is_valid():ids=delete_avatar_form.cleaned_data['choices']Avatar.objects.filter(id__in=ids).delete()request.user.message_set.create(message=dj._("Successfully deleted the requested avatars."))returndj.HttpResponseRedirect(next_overrideor_get_next(request))returndj.render_to_response('avatar/confirm_delete.html',extra_context,context_instance=dj.RequestContext(request,{'avatar':avatar,'avatars':avatars,'delete_avatar_form':delete_avatar_form,'next':next_overrideor_get_next(request),}))change=dj.login_required(change)
It works! Although after all of that, I have decided that in my opinion it’s just not worth the effort. It adds an extra level of indirection when tracing through the code, it litters the view with the dj namespace, and it’s harder to know what you have available to you. Maybe you like this style better, though. If so, what about this style do you like?