views:

363

answers:

4

I keep ending up at this situation where I want to use a dictionary very much like the one 'locals' gives back, but that only contains the variables in the limited scope of the function. Is there a way to do this in python?

A bit more about why I want to do this: I'm playing with Django and when I go to give my templates context, I am forced either to either manually make a dictionary (In violation with DRY principles) or pass in locals() which contains far more entries then are needed (wasteful). Is there perhaps something I'm missing with django which would alleviate the need of a python level solution?

To Clarify:

So, the case that I've hit repeatedly is where I have:

@render_to('my_template.html') 
def myview(request): 
    var1 = #blahblah 
    var2 = #... 
    # do stuff with vars 
    return {'var1': val1,'var2':val2}

So instead of repeating those variables and naming conventions, I'll do:

@render_to('my_template.html') 
def myview(request): 
    var1 = #blahblah 
    var2 = #... 
    # do stuff with vars 
    return locals()

Which I find cleaner, but I know its kind of sloppy since there are about 30 more entries in locals() then I actually need.

+3  A: 

How is passing a dictionary a violation of DRY? Django is all about DRY, so I doubt the standard behavior of it would directly violate it. In either case, however, I use a modified version of django-annoying to make the whole thing easier:

@render_to('my_template.html')
def myview(request):
    # figure stuff out...
    return {'var1':'val1','var2','val2'}

The render_to decorator takes care of the request context and all that good stuff. Works well.

If this doesn't help, I suggest rephrasing your question. Whatever you want to do messing around with locals() and such is rarely necessary especially in this kind of situation with Django.

Paolo Bergantino
I've added a clarification above (The code doesn't work in comments so well); regardless, django-annoying looks very cool, I was wanting a get_object_or_none today.
Albinofrenchy
+1: I agree it's not a violation of DRY at all. Indeed, by creating a value mapping specific to the template context, you're creating something that does not already exist (ie: the mapping), so you're not repeating anything. Often the items in the template context are built specifically for that template; you should always be able to completely re-work the logic of the view, but create a context dictionary that is always the same, thus isolating the template from the other app layers. Passing locals() to the template is rather dangerous, particularly in projects with multiple devs/designers.
Jarret Hardie
In the general case Jarret, I agree: That mapping needs to be able to conform to the template regardless of the views implementation. I think in practice though certain situations arise in which the local context of the function and the context of the template are the same; and I want a way to express that.I do agree that passing local() in is dangerous, which is one of the reasons I wrote this question.
Albinofrenchy
+5  A: 

I'm not sure I agree that making a dictionary is a violation of DRY, but if you really don't want to repeat anything at all, you could just define a 'context' dictionary at the top of the view and use dictionary keys instead of variables throughout the view.

def my_view(request):
    context = {}
    context['items'] = Item.objects.all()
    context['anothervalue'] = context['items'][2].name
    return render_to_response('template.html', context)
Daniel Roseman
+2  A: 

You say you don't like using locals() because it is "wasteful". Wasteful of what? I believe the dictionary it returns already exists, it's just giving you a reference to it. And even if it has to create the dictionary, this is one of the most highly optimized operations in Python, so don't worry about it.

You should focus on the code structure that best expresses your intention, with the fewest possibilities for error. The waste you are worried about is nothing to worry about.

Ned Batchelder
I think his concern is polluting the scope of his template with a bunch of unused variables
Jiaaro
+2  A: 

While I agree with many other respondents that passing either locals() or a fully specified dict {'var1':var1, 'var2': var2} is most likely OK, if you specifically want to "subset" a dict such as locals() that's far from hard either, e.g.:

loc = locals()
return dict((k,loc[k]) for k in 'var1 var2'.split())
Alex Martelli