web-dev-qa-db-fra.com

Django: analyser JSON dans mon modèle en utilisant Javascript

J'ai ceci à mon avis:

string_location = myaddress2
    geodata = []
    for place, (lat, lng) in g.geocode(string_location,exactly_one=False):
        geodata.append((place, (lat, lng)))

    geodata_results = len(geodata)

    data = {"geodata": geodata, "geodata_results":geodata_results }
    return render_to_response("business/business_view.html",
                              data, context_instance=RequestContext(request))

Comment pourrais-je "gérer"/convertir les géodonnées en JSON et le transmettre à mon modèle afin de pouvoir le "boucler" comme un tableau?

Ai-je raison de penser que je peux le faire de cette façon? Sinon, veuillez suggérer une meilleure solution.

Merci!

[~ # ~] mise à jour [~ # ~]

var geodata = "[["M. L. Quezon Street<br/>Mandaue City, Philippines", [10.351381999999999, 123.923535]], ["Talamban<br/>Cebu City, Philippines", [10.353527, 123.91352500000001]]]"; 

Je pense que le JSON n'est pas échappé? Comment échapper des caractères spéciaux à l'intérieur de la chaîne json? Je reçois toujours une erreur de nouvelle ligne.

Pour PHP, je voudrais json_encode () pour résoudre ce problème. Comme dans cet article: passez une chaîne PHP à une variable JavaScript (et échappez aux sauts de ligne) MAIS comment faire cela en Python/Django?

26
wenbert

Vous pouvez utiliser le module json intégré:

>>> import json
>>> geodata = [ ( "Here", (1003,3004) ), ("There", (1.2,1.3)) ]
>>> json.dumps(geodata)
'[["Here", [1003, 3004]], ["There", [1.2, 1.3]]]'

Vous pouvez ensuite simplement incorporer la chaîne résultante dans un script javascript:

<script type='text/javascript'>
var geodata = {{ geodata|safe }};
</script>
63
adamk

D'accord, j'ai résolu mon problème et j'aimerais répondre à ma propre question. J'ai pensé que ce serait mieux pour les autres utilisateurs ici.

Tout d'abord, récupérez le fichier ici: http://www.JSON.org/json_parse.js

var geodata = json_parse("{{geodata|escapejs}}");

Je viens d'utiliser escapejs: http://docs.djangoproject.com/en/dev/ref/templates/builtins/#escapejs

EDIT: Merci à Ignacio Vazquez-Abrams. C'est lui qui m'a aidé dans #python Freenode. J'aurais dû le créditer quand j'ai fait ce post. Je ne savais pas qu'il était dans Stackoverflow.

27
wenbert

Si vous ne vous souciez pas des anciens navigateurs tels que IE7, vous pouvez simplement écrire:

var geodata = JSON.parse("{{geodata|escapejs}}");

sans aucune bibliothèque supplémentaire. Voir http://caniuse.com/#feat=json pour les versions de navigateur qui prennent en charge JSON.parse ().

Je crois que la réponse la plus votée de @adamk a un problème potentiel avec XSS. Si le JSON contient "</script>", le navigateur l'interprète comme la fin de <script> tag. Il serait donc préférable d'utiliser le code de @wenbert ou le mien.

J'ai essayé de commenter la réponse directement, mais je n'ai pas assez de réputation pour le faire :)

12
Hiroshi Ichikawa

J'ai trouvé que je voulais souvent à la fois la version de l'objet (pour le code du modèle) et la version JSON (pour le code JavaScript), et je trouve un peu ennuyeux de passer les deux séparément au modèle quand on devrait bien faire.

Si vous voulez adopter l'approche de balise de modèle et ne voulez pas toutes les cloches et les sifflets de Argonauts Django alors vous pouvez utiliser cette balise de modèle qui a toujours fait l'affaire pour moi. Il peut ne pas être sûr à 100% contre les données non fiables, mais cela n'a jamais été un problème pour mes cas d'utilisation.

"""
Usage:

{% import json_tags %}

var = myJsObject = {{ template_var|to_json }};

Features:

- Built in support for dates, datetimes, lazy translations.
- Safe escaping of script tags.
- Support for including QueryDict objects.
- Support for custom serialization methods on objects via defining a `to_json()` method.
"""

import datetime
import json
from decimal import Decimal
from Django import template
from Django.http import QueryDict
from Django.utils.encoding import force_str
from Django.utils.functional import Promise
from Django.utils.safestring import mark_safe

register = template.Library()

ISO_DATETIME_FORMAT = '%Y-%m-%dT%H:%M:%S.%fZ'


def json_handler(obj):
    if callable(getattr(obj, 'to_json', None)):
        return obj.to_json()
    Elif isinstance(obj, datetime.datetime):
        return obj.strftime(ISO_DATETIME_FORMAT)
    Elif isinstance(obj, datetime.date):
        return obj.isoformat()
    Elif isinstance(obj, datetime.time):
        return obj.strftime('%H:%M:%S')
    Elif isinstance(obj, Decimal):
        return float(obj)  # warning, potential loss of precision
    Elif isinstance(obj, Promise):
        return force_str(obj)  # to support ugettext_lazy
    else:
        return json.JSONEncoder().default(obj)


@register.filter
def to_json(obj):
    def escape_script_tags(unsafe_str):
        # seriously: http://stackoverflow.com/a/1068548/8207
        return unsafe_str.replace('</script>', '<" + "/script>')

    # json.dumps does not properly convert QueryDict array parameter to json
    if isinstance(obj, QueryDict):
        obj = dict(obj)
    return mark_safe(escape_script_tags(json.dumps(obj, default=json_handler)))
2
Cory

Il existe de longue date ticket in Django about filter template that would output json in templates. Le principal problème est qu'il est difficile de trouver une solution qui peut être utilisé dans différents endroits du HTML sans introduire XSS. Pour l'instant, les méthodes suivantes peuvent être utilisées.

Stocker json dans l'attribut de données d'élément html:

<div data-geodata="{{json_dump_of_geodata}}"></div>
<script>
  var geodata = JSON.parse(
      document.querySelectorAll('[data-geodata]')[0].getAttribute('data-geodata')
  );
</script>

Ou en utilisant https://github.com/fusionbox/Django-argonauts

<script>
    var geodata = {{geodata|json}};
</script>

N'utilisez pas le filtre safe tant que vous n'êtes pas sûr à 100% que le json ne contient aucune donnée provenant de sources non fiables.

MISE À JOUR: Dans Django 2.1 json_script la balise a été ajoutée comme moyen officiel pour passer json du contexte du modèle au javascript.

1
Konstantin Alekseev