web-dev-qa-db-fra.com

Passer des données Python à JavaScript via Django

J'utilise Django et Apache pour servir des pages Web. Mon code JavaScript inclut actuellement un objet de données avec des valeurs à afficher dans divers widgets HTML en fonction de la sélection de l'utilisateur dans un menu de choix. Je veux dériver ces données d'un dictionnaire Python. Je pense savoir comment incorporer le code JavaScript dans le code HTML, mais comment puis-je incorporer l'objet de données dans ce script (à la volée) pour que les fonctions du script puissent l'utiliser?

En d'autres termes, je souhaite créer un objet ou un tableau JavaScript à partir d'un dictionnaire Python, puis insérer cet objet dans le code JavaScript, puis insérer ce code JavaScript dans le code HTML.

Je suppose que cette structure (par exemple, les données incorporées dans des variables dans le code JavaScript) est sous-optimale, mais en tant que débutant, je ne connais pas les alternatives. J'ai vu des descriptions des fonctions de sérialisation de Django, mais elles ne m'aident pas tant que je ne peux pas obtenir les données dans mon code JavaScript.

Je n'utilise pas (encore) une librairie JavaScript comme jQuery.

51
chernevik

nb voir la mise à jour 2018 en bas

Je recommande de ne pas mettre beaucoup de JavaScript dans vos modèles Django - il est généralement difficile d’écrire et de déboguer, en particulier à mesure que votre projet s’agrandit. Au lieu de cela, essayez d’écrire tout votre code JavaScript dans un fichier script séparé que votre modèle charge et en incluant simplement un objet de données JSON dans le modèle. Cela vous permet, par exemple, d’exécuter l’application JavaScript dans son intégralité avec quelque chose comme JSLint , de la minimiser, etc., et de le tester avec un fichier HTML statique, sans aucune dépendance de votre application Django. L'utilisation d'une bibliothèque telle que simplejson vous permet également d'économiser du temps consacré à l'écriture d'un code de sérialisation fastidieux.

Si vous ne supposez pas que vous construisez une application AJAX, vous pouvez simplement le faire comme ceci:

Dans la vue:

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, …})

Dans le modèle:

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

Notez que le type de données est important: si my_data est un simple nombre ou une chaîne provenant d'une source contrôlée qui ne contient pas HTML, telle qu'une date mise en forme, aucun traitement spécial n'est requis. S'il est possible de fournir des données non fiables fournies par un utilisateur, vous devrez les nettoyer en utilisant quelque chose comme les filtres escape ou escapejs et vous assurer que votre JavaScript gère les données en toute sécurité pour éviter le script intersite. attaques. 

En ce qui concerne les dates, vous voudrez peut-être aussi réfléchir à la manière dont vous passez les dates. J'ai presque toujours trouvé plus facile de les transmettre sous forme d'horodatages Unix:

À Django:

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

En JavaScript, en supposant que vous ayez fait quelque chose comme time_t = {{ time_t }} avec les résultats de l'extrait de code ci-dessus:

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

Pour finir, faites attention à UTC - vous souhaiterez que les fonctions de date Python et Django échangent des données au format UTC pour éviter des décalages gênants par rapport à l'heure locale de l'utilisateur.

EDIT: Notez que le setTime en javascript est en milliseconde alors que la sortie de time.mktime est en secondes. C'est pourquoi nous devons multiplier par 1000

Mise à jour 2018: J'aime toujours JSON pour les valeurs complexes, mais dans la décennie qui a suivi l'API de données HTML5 a atteint un support de navigateur quasi universel et il est très pratique pour passer des valeurs simples (non list/dict), en particulier si vous souhaitez que les règles CSS s'appliquent en fonction de ces valeurs et que vous ne vous souciez pas des versions non prises en charge d'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";
});

C'est un moyen judicieux d'exposer des données à CSS si vous souhaitez définir l'état d'affichage initial dans votre modèle Django et le mettre à jour automatiquement lorsque JavaScript met à jour l'attribut data-. J'utilise ceci pour masquer un widget de progression jusqu'à ce que l'utilisateur sélectionne un élément à traiter ou pour afficher/masquer de manière conditionnelle les erreurs en fonction des résultats d'extraction ou même pour afficher un nombre d'enregistrements actifs à l'aide de CSS, comme #some-element::after { content: attr(data-active-transfers); }.

75
Chris Adams

Si vous rencontrez des problèmes avec cela, assurez-vous de restituer votre objet Json en mode sans échec dans le modèle. Vous pouvez définir manuellement ceci comme ceci

<script type="text/javascript">
    data_from_Django = {{ my_data|safe }};
    widget.init(data_from_Django);
</script>
36
wilblack

Vous pouvez inclure des balises <script> dans vos modèles .html, puis créer vos structures de données, mais cela vous convient. Le langage de gabarit ne concerne pas uniquement le HTML, il peut également créer des littéraux d'objet Javascript.

Et Paul a raison: il peut être préférable d’utiliser un module JSON pour créer une chaîne JSON, puis d’insérer cette chaîne dans le modèle. Cela gérera mieux les problèmes de citation et traitera les structures profondes avec facilité.

3
Ned Batchelder

C'est sous-optimal. Avez-vous envisagé de transmettre vos données au format JSON à l'aide du sérialiseur intégré de Django?

2
Paul McMillan

Voir la réponse correspondante à cette question . Une option consiste à utiliser jsonpickle pour mettre en série des objets Python et des objets JSON/Javascript. Il englobe simplejson et gère des choses qui ne sont généralement pas acceptées par simplejson.

1
John Paulett

Mettre Java Script dans le modèle Django est plutôt toujours une mauvaise idée. 

Plutôt, car il y a des exceptions à cette règle.

Tout dépend du site et des fonctionnalités de votre code Java Script.

Il est préférable d’avoir des fichiers statiques séparés, comme JS, mais le problème est que chaque fichier a besoin d’un autre mécanisme de connexion/GET/demande/réponse. Parfois, pour les petites entreprises, deux liners codent en JS pour les mettre dans un modèle, utilisez ensuite le mécanisme Django templatetags - vous pouvez l’utiliser également dans d’autres modèles;)

À propos des objets - les mêmes. Si votre site a la faveur de AJAX construction/web2.0 - vous pouvez obtenir un très bon effet en effectuant des opérations de comptage/calcul du côté client. Si les objets sont petits - incorporés dans le modèle, s'ils sont grands - répondez-les à une autre connexion pour éviter la page de blocage pour l'utilisateur.

1
bluszcz

À partir de la mi-2018, l'approche la plus simple consiste à utiliser le module json de python. Simplejson est désormais obsolète. Attention, comme @wilblack le mentionne, vous devez empêcher la capture automatique de Django en utilisant le filtre safe ou la balise autoescape avec une option off. Dans les deux cas, dans la vue, vous ajoutez le contenu du dictionnaire au contexte. 

viewset.py

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

et ensuite, dans le modèle, vous ajoutez comme @wilblack suggéré:

template.html

<script> my_data = {{ my_dictionary|safe }}; </script>

0
Daniel Kislyuk