Pasando objetos de Django a Javascript DOM

Estoy tratando de pasar un conjunto de consultas de Django a una plantilla con javascript.

He intentado diferentes enfoques para resolver esto:

1. Enfoque normal: Javascript se complica al intentar analizar el objeto debido a la nomenclatura [& gt Object: ID & lt, & gt Object: ID & lt, …]

Django View

django_list = list(Some_Object.objects.all()) 

Plantilla HTML + JS

  var js_list = {{django_list}};  

2. Enfoque JSON: Django falla al convertir la lista de objetos a una cadena json que no es serializable por JSON

Django View

 django_list = list(Some_Object.objects.all()) json_list = simplejson.dumps(django_list) 

Plantilla HTML + JS

  var js_list = {{json_list}};  

Por lo tanto, necesito un poco de ayuda aquí 🙂

¿Alguien tiene alguna sugerencia / solución?

¡Gracias!

Misma pregunta, respuesta “Mejor” ( más reciente ): Django Queryset a dic para usar en json

Respuesta de vashishtha-jogi :

Un mejor enfoque es utilizar DjangoJSONEncoder. Tiene soporte para decimal.

 import json from django.core.serializers.json import DjangoJSONEncoder prices = Price.objects.filter(product=product).values_list('price','valid_from') prices_json = json.dumps(list(prices), cls=DjangoJSONEncoder) 

Muy fácil de usar. No hay que saltar a través de aros para convertir campos individuales a flotar.

Actualización: se cambió la respuesta para usar json incorporado en lugar de simplejson.

Esta es una respuesta que aparece tan a menudo en mis búsquedas de Google y tiene tantas vistas, que parece una buena idea actualizarla y evitar que alguien más se entere. Asume Django 1.5 .

Ok, he encontrado la solución!

Principalmente fue por no citar los resultados. Cuando Javascript intentaba analizar el objeto, este no se reconocía como una cadena.

Entonces, el primer paso es:

 var js_list = {{django_list}}; 

cambiado a:

 var js_list = "{{django_list}}"; 

Después de esto me di cuenta de que Django se estaba escapando de los personajes, así que tuve que reemplazarlos así:

  var myJSONList = (("{{json_list}}").replace(/&(l|g|quo)t;/g, function(a,b){ return { l : '<', g : '>', quo : '"' }[b]; })); myData = JSON.parse( myJSONList ); 

Nota: Intenté evitar que se escapen los caracteres de Django usando esto :

 var js_list = "{{json_list|safe}}"; 

Pero esto no funciona porque se confunde con las citas.

Finalmente encontré una manera de evitar la lógica en el backend de convertir a JSON antes de enviarlo a Javascript:

 var myDjangoList = (("{{django_list |safe}}").replace(/&(l|g|quo)t;/g, function(a,b){ return { l : '<', g : '>', quo : '"' }[b]; })); myDjangoList = myDjangoList.replace(/u'/g, '\'') myDjangoList = myDjangoList.replace(/'/g, '\"') myData = JSON.parse( myDjangoList ); 

Estoy seguro de que esto se puede mejorar, se lo dejo a usted;)

Gracias por tus respuestas

Espero que ayude a alguien mas!

Los querysets de Django son serializables por JSON . Algunos tipos de campos (como la fecha, aparentemente), no pueden ser serializados en. Una solución para los objetos de fecha se publica en otra pregunta en JSON y Python .

Recomendaría crear diccionarios directamente en el propio JavaScript. Dados modelos como este:

 class Article(models.Model): title = models.CharField(max_length=100) slug = models.SlugField() content = models.TextField() class Author(models.Model): article = models.ForeignKey("Article", related_name="authors") first_name=models.CharField(max_length=100) last_name=models.CharField(max_length=100) 

Haría algo como esto en la plantilla:

  

Si quizás redactó la pregunta un poco mal y no planea insertar código en una etiqueta y realmente necesita JSON por alguna razón, simplemente haría un bucle en la vista y crearía una lista de dict , que JSON no tiene problemas para serializar, y JavaScript no tiene problemas para comprender.

EDITAR: por favor no use este método, vea la respuesta de @agconti.

Utilice el filtro de escapejs: https://docs.djangoproject.com/en/1.4/ref/templates/builtins/#escapejs

Ejemplo de volcar una lista:

 var foo = [{% for x in y %}'{{ x|escapejs }}',{% endfor %}] 

Puedes usar la combinación de filtro seguro y escape incorporado en Django.

 var json_string = unescape({{json_list | safe | escapejs}}); var json_data = JSON.parse(json_string); 

Su problema es que, como muy a menudo, sus requisitos no están bien especificados. ¿Cómo quieres que se vea exactamente el JSON? Usted dice que quiere “serializar el queryset”, pero ¿en qué formato? ¿Desea que todos los campos de cada instancia de modelo, una selección o solo la representación Unicode? Cuando haya respondido esa pregunta, sabrá cómo resolver su problema.

Un enfoque, por ejemplo, podría ser usar el método de búsqueda de values para generar un diccionario de campos para cada instancia y serializarlo (primero debe convertirlo en una lista):

 data = SomeObject.objects.values('field1', 'field2', 'field3') serialized_data = simplejson.dumps(list(data)) 

Tienes que marcar la cadena como segura para asegurarte de que no se haya escapado.

En uno de mis proyectos lo uso así:

 # app/templatetag/jsonify.py from django import template from django.utils.safestring import mark_safe import json register = template.Library() @register.filter def jsonify(list): return mark_safe(json.dumps(list)) 

y en la plantilla

 {% load jsonify %}  

pero puede preferir simplemente agregar mark_safe o usar | safe en la plantilla para evitar todos > cosas

Si el problema es para manejar un objeto Python complejo, es posible que tenga que hacer su controlador de esta manera: JSON datetime entre Python y JavaScript

Django ofrece ayuda integrada para el escenario que intenta hacer aquí. Es algo parecido a esto:

Tiene una secuencia de python, lista, diccionario, etc. en su vista, llamémoslo py_object . Un enfoque es jsonificarlo antes de pasarlo al motor de renderizado.

 from django.shortcuts import render_to_response import json 

Luego, más tarde, use así …

 render_to_response('mypage.html',{'js_object':json.dumps(py_object)}) 

En tu plantilla, luego usa el filtro safe para importar el objeto ya jsonized de python a javascript, como esto …

 data = {{ js_object|safe }} 

Eso debería resolver tu problema, espero.

Respuesta consolidada (mi env: Django 2.0)

En views.py

 import json data= [] // fil the list context['mydata'] = json.dumps({'data':data}) 

En plantilla

   

Desde Django 2.1 existe la etiqueta de plantilla json-script . De los documentos:

json_script

Produce de forma segura un objeto Python como JSON, envuelto en una etiqueta, listo para usar con JavaScript.

Argumento: HTML “id” de la etiqueta.

Por ejemplo:

 {{ value|json_script:"hello-data" }} 

Si valor es el diccionario {'hello': 'world'} , la salida será:

  

Se puede acceder a los datos resultantes en JavaScript de esta manera:

 var value = JSON.parse(document.getElementById('hello-data').textContent); 

Los ataques XSS se mitigan al escapar de los caracteres “<”, “>” y “&”. Por ejemplo, si el valor es {'hello': 'world&'} , la salida es:

  

Esto es compatible con una política de seguridad de contenido estricta que prohíbe la ejecución de secuencias de comandos en la página. También mantiene una separación limpia entre los datos pasivos y el código ejecutable.