Plantilla Django y el truco de los locales.

Los libros de django dan el truco local para evitar escribir una larga lista de parámetros como diccionario de contexto http://www.djangobook.com/en/2.0/chapter04/

Se lo recomienda a los progtwigdores perezosos, pero señala algunos gastos generales que pueden tener un impacto en el rendimiento.

Me gustaría saber si algunos de ustedes están usando el truco de los locales en aplicaciones reales. ¿Lo recomiendas o es una mala práctica?

No me gusta la repetición, creo que “DRY”, “Don’t Repeat Yourself”, es un principio de progtwigción clave. Como consecuencia, he usado locals() en situaciones similares. La representación de la plantilla Django está lejos de ser la única situación de este tipo: el caso general es “una función u operador que acepta un dict, pero no le importa si el dict contiene entradas adicionales”. (Por ejemplo, el formato de cadena normal en Python es otro de estos casos).

Sin embargo, hay un principio compensatorio: los progtwigs deben ser comprensibles de la manera más localizada posible, lo que ayuda al mantenimiento y la refactorización (ya que evita la necesidad de estudiar otros archivos para verificar qué refactorizaciones son aceptables). Esto sugiere, para el caso de locals() , que está bien si la plantilla (o el formato de cadena, etc.) es un literal local (un caso raro en el que probablemente solo se estén utilizando pocas variables y, por lo tanto, locals() no es una gran ganancia. -), pero problemático en el caso normal donde la plantilla vive en un archivo diferente.

Por lo tanto, usar locals() , en la mayoría de los casos, dificulta seriamente la refactorización. En casi todas las situaciones en Python, las variables locales y sus nombres se pueden cambiar libremente como parte de una refactorización local, ya que no tienen un efecto “externamente visible” … pero al usar locals() rompe eso, de repente no se puede cambie el nombre de una variable a un nombre diferente que ofrezca una mayor claridad, refuerce el flujo del código de una manera que elimine la necesidad de una variable, etc, etc., sin tener que estudiar cada vez más un archivo de plantilla por separado para verificar si el nombre anterior no es necesario ( y posiblemente la edición del archivo de plantilla, que puede ser no trivial, por ejemplo, si se mantiene en varios lenguajes naturales diferentes para propósitos de i18n / L10n).

Como consecuencia, además del problema secundario de rendimiento, existe una fuerte presión contra el uso de locals() en el código “serio”, de “producción”: código que requiere un mantenimiento a largo plazo y, por lo tanto, una refactorización y una ubicación fáciles. Entonces, cuando estoy “progtwigndo lo mejor que sé”, en lugar de “cortar esquinas”, soy consciente de que es mejor evitar a los locals()

Los valores que desea tener en el contexto en el que se representa la plantilla no están necesariamente “naturalmente” disponibles como nombres locales, después de todo; tal vez algunos o muchos de ellos sean resultados de cálculos, elementos de listas o diccionarios, y similares. En este caso, la tentación de “cortar esquinas” con locals() es más fácil de evitar si simplemente acumula esos valores en un diccionario adecuado en lugar de asignarles nombres pelados locales.

No es la compensación más fácil, porque dos buenos principios (evitar la repetición y tener una buena localidad) son inevitablemente conflictivos, por lo tanto, ¡buena pregunta! Y no es del todo susceptible a las respuestas blancas o negras, por lo que he tratado de expandirme en ambos lados. Al final, creo que es uno de esos aspectos de “estilo” donde un equipo de progtwigción puede ser bien aconsejado para adoptar una guía de estilo de uniforme de equipo y atenerse a ella, al menos elimina la necesidad de tomar una decisión una y otra vez el momento en que surge el problema, y ​​produce una base de código más homogénea (y, por lo tanto, mantenible). [[Tengo que confesar que este punto específico nunca se ha abordado explícitamente en las pautas de estilo de los equipos en los que he estado, aunque, ¡muchos otros sí! -)]]

A menudo pensé en hacer lo siguiente, pero no estoy seguro de si es realmente útil.

 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__) 

No me gusta, personalmente. Probablemente no haya ninguna razón para mi preferencia, aparte del antiguo dicho de Python: “Explícito es mejor que implícito”. Me gusta saber exactamente qué está pasando en mis plantillas.

Lo he usado sin ningún problema (hasta ahora!).

No soy especialmente aficionado a escribir, por eso me gusta. Código como

 'customer' : customer, 'invoice' : invoice, 'date' : date 

Simplemente me parece ridículo y si puedo evitarlo lo haré. Una de las razones por las que me gusta Python es su falta de repetitivo (aunque esto no es realmente repetitivo, pero es similar).

Supongo que depende de cuántas variables locales defina en su función.

Si coincide exactamente con el número que desea que regrese a su plantilla, o si las variables ‘extra’ son estructuras simples como enteros o booleanos, supongo que no tiene sentido devolverlos explícitamente, ya que esto requiere más trabajo.

Pero, por otro lado, si su vista tiene muchas variables “auxiliares” complejas, como las instancias de su modelo que utiliza en la vista para generar los datos que desea enviar a la plantilla, es posible que desee considerar el uso explícito. Variables para volver a la plantilla.

Sé que este es un hilo viejo … actualmente render_to_response está en desuso. Utilice render en lugar de locales (). Pasar por todos los locales es una mala práctica. Aquí hay un ejemplo de views.py:

 from django.shortcuts import render from django.contrib.auth.decorators import login_required @login_required def mybooks(request): entries = Book.objects.all() return render(request, 'mybooks.html', {'entries': entries}) 

Para reducir el desorden en views.py mientras se mantienen las cosas explícitas: En controllers.py :

 import sys def auto_context(the_locals=None): # Take any variable in the locals() whose name ends with an underscore, and # put it in a dictionary with the underscore removed. if the_locals is None: # We can access the locals of the caller function even if they # aren't passed in. caller = sys._getframe(1) the_locals = caller.f_locals return dict([ (key[:-1], value) for (key, value) in the_locals.items() if key[-1] == "_"]) 

En views.py :

 from app.controllers import auto_context def a_view(request): hello_ = "World" # This will go into the context. goodnight = "Moon" # This won't. return render(request, "template.html", auto_context()) 

En template.html , usa {{ hello }} .

Es poco probable que le dé un nombre a una variable que termine en un guión bajo accidentalmente. Así que sabrás exactamente lo que está pasando en la plantilla. Utilice auto_context() o equivalentemente auto_context(locals()) . ¡Disfrutar!

Estoy de acuerdo con Alex. No veas el punto de crear una instancia de clase (como lo sugiere niels) cuando puedes hacer esto:

 def my_view(request, id): customer = .. invoice = .. date = .. return render_to_response('xxx,html', locals()) 

Si desea una razón de rendimiento, las búsquedas de puntos son más lentas.

Si desea un motivo de mantenimiento, se trata de menos líneas de código, incluso más legibles y una menos estructuras innecesarias.