1. b.93z.org
  2. Notes

Abuse of locals() in Django views

Once I saw strange blog entry saying that this code

def list_items(request):
    items = Item.objects.all()
    return render(request, 'items.html', locals())

is better than this

def list_items(request):
    data = {}
    items = Item.objects.all()
    data['items'] = items
    return render(request, 'items.html', data)

because “you end up both having a consistent naming policy and you don’t have to waste lines doing data dict assignments”.

This is disputable statement. Comparison is not quite fair: such “named” context dicts are rare. In most cases it is either dictionary class or dictionary literal passed directly to rendering function as an argument without any name assignments: render(request, 'tmpl.html', {'some': 'data'}). Plus, consistent naming policy and “wasted lines” have nothing to do with locals(). Actually, such abuse of this built-in function may lead to bugs (including privacy ones). These bugs potentially lead to serious lawsuits against owner (and/or developer) of application.

locals(), according to documentation, “updates and returns a dictionary representing the current local symbol table”. With CPython, PyPy, and Jython it returns the same dictionary (didn’t check other implementations, though). So, in first snippet, locals() will return dict with two pairs, with two keys: request, and items. How that may lead to disaster?

When you’re passing things explicitly (explicit is better than implicit), you can quickly grasp what context template will have (though Django “helps” here via context processors) and what happens on lines between def and return. Sure, setting template context variables is more verbose, but it prevents context pollution and accidental disclosure of confidential data:

def show_item(request, pk):
    item = get_object_or_404(Item, pk=pk)
    secret_data = get_secret_data(item)
    item.smth = calculate_smth(secret_data)
    # ...do something else with secret_data
    return render(request, 'items/show_item.html', {'item': item})

It this case locals() will return dict with secret_data. Explicit declaration prevents, at some extent, template writer to unintentionally leave sensitive data output (“debugging”) template code in codebase (or at least it prevents output of such data). Also, in most projects, templates are frontend developer’s expertise. That person may be unfamiliar with Python, thus explicit “list” of objects available in templates is a good thing, as it is much easier to read.

© 2008–2017 93z.org