Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django template and the locals trick

Tags:

python

django

The django books gives the local trick in order to avoid to type a long list of parameters as context dictionnary

http://www.djangobook.com/en/2.0/chapter04/

Example:

def current_datetime(request):     dt_now = datetime.datetime.now()     return render_to_response('current.html', {'dt_now': dt_now}) 

becomes:

def current_datetime(request):     dt_now = datetime.datetime.now()     return render_to_response('current.html', locals()) 

It recommends this to lazy programmers but points out some overhead which may have an impact on performance.

I would like to know if some of you are using the locals trick on real applications. Do you recommend it or is it a bad practice?

like image 592
luc Avatar asked Dec 14 '09 15:12

luc


People also ask

What is locals in Django?

locals() is a Python built-in function that according to the official Python documentation: Updates and returns a dictionary representing the current local symbol table. Free variables are returned by locals() when it is called in function blocks, but not in class blocks.

What does {% mean in Django?

{% %} is basically used when you have an expression and are called tags while {{ }} is used to simply access the variable.

Where can I find Django templates?

To configure the Django template system, go to the settings.py file and update the DIRS to the path of the templates folder. Generally, the templates folder is created and kept in the sample directory where manage.py lives. This templates folder contains all the templates you will create in different Django Apps.

Which Django template syntax allows to use the for loop?

To create and use for loop in Django, we generally use the “for” template tag. This tag helps to loop over the items in the given array, and the item is made available in the context variable.


2 Answers

I don't like repetition -- I think "DRY", "Don't Repeat Yourself", is a key programming principle. As a consequence, I have indeed used locals() in similar situations. Django template rendering is far from the only situation of this kind: the general case is "a function or operator which accepts a dict, but doesn't mind if the dict contains extra entries". (For example, ordinary string formatting in Python is another such case).

However, there's a countervailing principle: programs should be understandable in as localized a way as feasible -- that helps maintenance and refactoring (as it obviates the need to study other files to check what refactorings are acceptable). This suggests, for the locals() case, that it's OK if the template (or string format, etc) is a local literal (a rare case where only few variables are probably being used and thus locals() is not a huge win!-), but problematic in the normal case where the template lives in a different file.

So, using locals(), in most cases, seriously hampers refactoring. In almost every situation in Python, local variables and their names can freely be changed as part of a local refactoring, since they have no "externally visible" effect... but using locals() breaks that -- suddenly you can't safely rename a variable to a different name offering better clarity, refactor code flow in a manner that removes the need for a variable, etc, etc, without each and every time studying a separate template file to check if the old name might not be needed (and possibly editing the template file, which can be non-trivial, for example if it's maintained in several different natural languages for i18n/L10n purposes).

As a consequence, in addition to the secondary issue of performance, there is strong pressure against using locals() in "serious", "production" code -- code that does need long term maintenance and therefore easy refactoring and locality. So, when I'm "programming as best I know how", rather than "cutting corners", I'm aware I had better avoid locals().

The values that you want to have in the context in which the template is rendered are not necessarily "naturally" available as local bare-names, after all; maybe some or many of them are results of computations, items from lists or dictionaries, and the like. In this case, the temptation to "cut corners" with locals() is easier to avoid if you just accumulate those values into a suitable dictionary rather than assigning them local bare-names.

It's not the easiest tradeoff, because two good principles (avoiding repetition, and having good locality) are inevitably clashing -- therefore, good question! And not one entirely susceptible to sharp black or white answers, which is why I've tried to expand on both sides. In the end, I think it's one of those "style" aspects where a programming team might be well advised to adopt a team-uniform style guideline and stick to it -- at least it removes the need to make a decision over and over every time the issue arises, and produces a more homogeneous (and thereby maintainable) code base. [[I have to confess that this specific point has never been explicitly addressed in the style guidelines of teams I've been in, though, although many others have!-)]]

like image 192
Alex Martelli Avatar answered Sep 25 '22 12:09

Alex Martelli


I often thought of doing the following, but I am not sure if it is really helpful.

class MyStruct(object):      pass  def my_view(request, id):     c = MyStruct()     c.customer = ..     c.invoice = ..     c.date = ..     return render_to_response('xxx,html',c.__dict__) 
like image 32
niels Avatar answered Sep 25 '22 12:09

niels