60 votes

Transférer des données Python vers JavaScript via Django

J'utilise Django et Apache pour servir des pages Web. Mon code JavaScript comprend 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 intégrer le code JavaScript dans le HTML, mais comment intégrer 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 veux créer un objet ou un tableau JavaScript à partir d'un dictionnaire Python, puis insérer cet objet dans le code JavaScript, et enfin insérer ce code JavaScript dans le HTML.

Je suppose que cette structure (par exemple, des données intégré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 faire entrer les données dans mon code JavaScript en premier lieu.

Je n'utilise pas (encore) une bibliothèque JavaScript comme jQuery.

0 votes

82voto

Chris Adams Points 2356

N.b. voir la mise à jour de 2018 au bas de la page

Je vous déconseille de mettre beaucoup de JavaScript dans vos modèles Django - il a tendance à être difficile à écrire et à déboguer, en particulier lorsque votre projet s'étend. Essayez plutôt d'écrire tout votre JavaScript dans un fichier script distinct que votre modèle charge et d'inclure simplement un objet de données JSON dans le modèle. Cela vous permet de faire des choses comme exécuter votre application JavaScript entière à travers quelque chose comme JSLint et vous pouvez le tester avec un fichier HTML statique sans aucune dépendance sur votre application Django. L'utilisation d'une bibliothèque comme simplejson vous permet également d'économiser le temps passé à écrire du code de sérialisation fastidieux.

Si vous ne supposez pas que vous êtes en train de construire une application AJAX, cela peut être fait simplement 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 importe : si my_data est un simple nombre ou une chaîne de caractères provenant d'une source contrôlée qui ne contient pas de HTML, comme une date formatée, aucune manipulation spéciale n'est requise. S'il est possible que des données non fiables soient fournies par un utilisateur, vous devrez les assainir en utilisant quelque chose comme la fonction s'échapper o escapejs et assurez-vous que votre JavaScript traite les données en toute sécurité afin d'éviter scripting intersite attaques.

En ce qui concerne les dates, vous pouvez également réfléchir à la manière dont vous les transmettez. J'ai presque toujours trouvé plus facile de les transmettre sous forme de timestamps Unix :

Dans 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 ci-dessus :

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

Enfin, tenez compte de l'UTC : les fonctions de date de Python et de Django doivent échanger des données en UTC pour éviter tout décalage gênant par rapport à l'heure locale de l'utilisateur.

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

Mise à jour de 2018 : j'aime toujours JSON pour les valeurs complexes mais dans la décennie qui s'est écoulée. l'API de données HTML5 a atteint support quasi universel des navigateurs et c'est très pratique pour transmettre des valeurs simples (non-list/dict), surtout si vous souhaitez que des 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";
});

Il s'agit d'un moyen efficace d'exposer des données à CSS si vous souhaitez définir l'état initial de la vue dans votre modèle Django et le mettre à jour automatiquement lorsque JavaScript met à jour le fichier data- attribut. Je l'utilise par exemple pour masquer un widget de progression jusqu'à ce que l'utilisateur sélectionne quelque chose à traiter, pour afficher/masquer de manière conditionnelle les erreurs en fonction des résultats de la recherche ou même pour afficher le nombre d'enregistrements actifs à l'aide d'une feuille de style CSS, par exemple #some-element::after { content: attr(data-active-transfers); } .

0 votes

Merci. J'avais prévu de servir le javascript comme un fichier média, similaire à une feuille de style css. Cela semble être une meilleure solution que d'incorporer les données dans le javascript, bien que je doive apprendre un peu de JSON et écrire du code côté serveur pour gérer les demandes de données.

0 votes

C'est une bonne idée. Ce que j'aime vraiment dans cette approche, c'est qu'il est trivial d'écrire une vue Django qui renvoie du JSON (si vous le faites souvent, regardez django-piston pour créer des API REST) et il est très facile de tester des parties isolées de cette façon.

0 votes

Je ne l'ignore pas ! Je développe simplement mes connaissances en matière d'écriture et d'utilisation de javascript jusqu'au point où je l'utilise réellement. Je prévois maintenant d'utiliser JSON pour transmettre des métadonnées afin de déterminer quels widgets sont affectés par le choix du menu, mais cela m'a demandé d'en apprendre davantage sur la création et l'accès aux structures de données javascript.

45voto

wilblack Points 147

Si vous rencontrez un problème, assurez-vous que votre objet json est rendu en mode sécurisé dans le modèle. Vous pouvez le définir manuellement comme suit

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

3voto

Ned Batchelder Points 128913

Vous pouvez inclure <script> dans vos modèles .html, puis construisez vos structures de données de la manière qui vous convient le mieux. Le langage de gabarit n'est pas seulement pour le HTML, il peut aussi faire des littéraux d'objet Javascript.

Et Paul a raison : il serait 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 permettra de gérer au mieux les problèmes de citation et de traiter facilement les structures profondes.

1voto

Paul McMillan Points 11723

C'est sous-optimal. Avez-vous envisagé de transmettre vos données au format JSON en utilisant le sérialiseur intégré de Django ?

0 votes

Je me suis dit que j'allais apprendre quelques notions de base avant de me lancer dans les acronymes. Mais il semble que je puisse soit apprendre du JSON, soit construire une solution à partir d'éléments de base, que je mettrai au rebut une fois que j'aurai appris du JSON.

0voto

bluszcz Points 1536

Mettre un script Java intégré dans un modèle Django, c'est plutôt toujours une mauvaise idée.

Plutôt car il existe des exceptions à cette règle.

Tout dépend du site et de la fonctionnalité de votre code script Java.

Il est préférable d'avoir des fichiers statiques séparés, comme les JS, mais le problème est que chaque fichier séparé nécessite un autre mécanisme de connexion/GET/requête/réponse. Parfois, pour les petits codes d'une ou deux lignes de JS, il est possible de les placer dans un modèle, puis d'utiliser le mécanisme des templatetags de Django - vous pouvez l'utiliser dans d'autres modèles ;)

Pour les objets, c'est pareil. Si votre site est construit en AJAX/web2.0, vous pouvez obtenir un très bon effet en plaçant certaines opérations de comptage/mathématiques du côté client. Si les objets sont petits, incorporez-les dans le modèle, s'ils sont grands, répondez-les dans une autre connexion pour éviter de faire traîner la page pour l'utilisateur.

0 votes

Oui, et vous avez intégré json dans django ;) Oubliez le xml :P

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X