Estoy usando Django y Apache para servir páginas web. Mi código JavaScript actualmente incluye un objeto de datos con valores que se mostrarán en varios widgets HTML basados en la selección del usuario de un menú de opciones. Quiero derivar estos datos de un diccionario de Python. Creo que sé cómo incrustar el código JavaScript en el HTML, pero ¿cómo incrustar el objeto de datos en ese script (sobre la marcha) para que las funciones del script puedan usarlo?

Dicho de otra manera, quiero crear un objeto o matriz de JavaScript a partir de un diccionario de Python, luego insertar ese objeto en el código de JavaScript y luego insertar ese código de JavaScript en el HTML.

Supongo que esta estructura (por ejemplo, datos incrustados en variables en el código JavaScript) es subóptima, pero como novato no conozco las alternativas. He visto informes de las funciones de serialización de Django, pero estas no me ayudan hasta que puedo obtener los datos en mi código JavaScript en primer lugar.

No estoy (todavía) usando una biblioteca de JavaScript como jQuery.

57
chernevik 18 sep. 2009 a las 21:52

7 respuestas

La mejor respuesta

Nótese bien. ver actualización de 2018 en la parte inferior

Recomiendo no poner mucho JavaScript en sus plantillas de Django: tiende a ser difícil de escribir y depurar, especialmente a medida que su proyecto se expande. En su lugar, intente escribir todo su JavaScript en un archivo de script separado que cargue su plantilla y simplemente incluya solo un objeto de datos JSON en la plantilla. Esto le permite hacer cosas como ejecutar toda su aplicación JavaScript a través de algo como JSLint, minificarlo, etc. y puede pruébelo con un archivo HTML estático sin ninguna dependencia de su aplicación Django. El uso de una biblioteca como simplejson también le ahorra el tiempo dedicado a escribir código de serialización tedioso.

Si no está asumiendo que está creando una aplicación AJAX, esto simplemente se podría hacer así:

En la vista:

from django.utils import simplejson


def view(request, …):
    js_data = simplejson.dumps(my_dict)
    …
    render_template_to_response("my_template.html", {"my_data": js_data, …})

En la plantilla:

<script type="text/javascript">
    data_from_django = {{ my_data }};
    widget.init(data_from_django);
</script>

Tenga en cuenta que el tipo de datos es importante: si my_data es un número simple o una cadena de una fuente controlada que no contiene HTML, como una fecha formateada, no se requiere un manejo especial. Si es posible que un usuario proporcione datos no confiables, deberá desinfectarlos con algo como escape o escapejs filtros y asegúrese de que su JavaScript maneja los datos de manera segura para evitar ataques cross-site scripting.

En cuanto a las fechas, es posible que también desee pensar en cómo pasar las fechas. Casi siempre me ha resultado más fácil pasarlos como marcas de tiempo de Unix:

En Django:

time_t = time.mktime(my_date.timetuple())

En JavaScript, suponiendo que haya hecho algo como time_t = {{ time_t }} con los resultados del fragmento anterior:

my_date = new Date();
my_date.setTime(time_t*1000);

Finalmente, preste atención a UTC: querrá que las funciones de fecha de Python y Django intercambien datos en UTC para evitar cambios embarazosos desde la hora local del usuario.

EDITAR: Tenga en cuenta que setTime en javascript está en milisegundos, mientras que la salida de time.mktime es segundos. Es por eso que necesitamos multiplicar por 1000

Actualización 2018: todavía me gusta JSON para valores complejos, pero en la década intermedia la API de datos HTML5 ha alcanzado casi compatible con el navegador universal y es muy conveniente para pasar simple ( valores no listados / dict), especialmente si desea que se apliquen reglas CSS basadas en esos valores y no le interesan las versiones no compatibles de Internet Explorer.

<div id="my-widget" data-view-mode="tabular">…</div>

let myWidget = document.getElementById("my-widget");
console.log(myWidget.dataset.viewMode); // Prints tabular
somethingElse.addEventListener('click', evt => {
    myWidget.dataset.viewMode = "list";
});

Esta es una forma ordenada de exponer datos a CSS si desea establecer el estado de vista inicial en su plantilla de Django y hacer que se actualice automáticamente cuando JavaScript actualice el atributo data-. Lo uso para cosas como ocultar un widget de progreso hasta que el usuario seleccione algo para procesar o para mostrar / ocultar condicionalmente errores basados en resultados de búsqueda o incluso algo como mostrar un recuento de registros activo usando CSS como #some-element::after { content: attr(data-active-transfers); }.

78
Chris Adams 22 jun. 2018 a las 15:02

Puede incluir etiquetas <script> dentro de sus plantillas .html, y luego construir sus estructuras de datos, sin embargo, es conveniente para usted. El lenguaje de plantilla no es solo para HTML, también puede hacer literales de objetos Javascript.

Y Paul tiene razón: podría ser mejor usar un módulo json para crear una cadena JSON, luego insertar esa cadena en la plantilla. Eso manejará mejor los problemas de citas y tratará estructuras profundas con facilidad.

3
Ned Batchelder 18 sep. 2009 a las 18:19

A mediados de 2018, el enfoque más simple es usar el módulo JSON de Python, simplejson ahora está en desuso. Tenga en cuenta que, como @wilblack menciona, debe evitar el autoescapado de Django utilizando el filtro safe o la etiqueta autoescape con una opción off. En ambos casos, en la vista, agrega los contenidos del diccionario al contexto

viewset.py

import json
 def get_context_data(self, **kwargs):
    context['my_dictionary'] = json.dumps(self.object.mydict)

Y luego en la plantilla que agregas como @wilblack sugirió:

template.html

<script>
    my_data = {{ my_dictionary|safe }};
</script>
4
kenlukas 10 sep. 2019 a las 11:44

Es subóptimo. ¿Ha considerado pasar sus datos como JSON usando el serializador incorporado de django para eso?

2
Paul McMillan 18 sep. 2009 a las 18:06

Consulte la respuesta relacionada a esta pregunta. Una opción es usar jsonpickle para serializar entre objetos Python y objetos JSON / Javascript . Envuelve simplejson y maneja cosas que típicamente no son aceptadas por simplejson.

1
Community 23 may. 2017 a las 12:02

Para cualquiera que pueda tener problemas con esto, asegúrese de representar su objeto json en modo seguro en la plantilla. Puedes configurarlo manualmente de esta manera

<script type="text/javascript">
    data_from_django = {{ my_data|safe }};
    widget.init(data_from_django);
</script>
40
wilblack 8 nov. 2012 a las 20:13

Poner Java Script incrustado en la plantilla de Django es bastante siempre una mala idea.

Más bien , porque hay algunas excepciones a esta regla.

Todo depende del sitio y la funcionalidad de su código Javascript.

Es mejor tener archivos estáticamente separados, como JS, pero el problema es que cada archivo separado necesita otro mecanismo de conexión / GET / solicitud / respuesta. A veces, para uno pequeño, dos liners codifican JS para poner esto en la plantilla, bun y luego usan el mecanismo django templatetags; puede usarlo en otras plantillas;)

Sobre objetos: lo mismo. Si su sitio tiene AJAX construction / web2.0 como favor, puede lograr un efecto muy bueno al poner algunas operaciones de conteo / matemáticas en el lado del cliente. Si los objetos son pequeños, incrustados en la plantilla, si son grandes, responda en otra conexión para evitar la página de Hangind para el usuario.

1
bluszcz 19 sep. 2009 a las 08:47