J'utilise Django sur Appengine. J'utilise la fonction Django reverse()
partout, en conservant le plus possible DRY.
Cependant, j'ai du mal à l'appliquer à mon javascript côté client. Il existe une classe JS qui charge certaines données en fonction d'un ID transmis. Existe-t-il un moyen standard de ne pas coder en dur l'URL à partir de laquelle ces données devraient provenir?
var rq = new Request.HTML({
'update':this.element,
}).get('/template/'+template_id+'/preview'); //The part that bothers me.
Il existe une autre méthode, qui n'exige pas d'exposer la structure entière de l'URL ou les demandes ajax pour résoudre chaque URL. Bien que ce ne soit pas vraiment beau, il bat les autres avec simplicité:
var url = '{% url blog_view_post 999 %}'.replace (999, post_id);
(Les URLs blog_view_post
ne doivent pas contenir le chiffre magique 999
bien sûr.)
Ayant tout juste lutté avec cela, j'ai proposé une solution légèrement différente.
Dans mon cas, je voulais qu'un script JS externe appelle un appel AJAX lors d'un clic sur un bouton (après un autre traitement).
Dans le HTML, j'ai utilisé un attribut personnalisé HTML-5 donc
<button ... id="test-button" data-ajax-target="{% url 'named-url' %}">
Ensuite, dans le javascript, tout simplement
$.post($("#test-button").attr("data-ajax-target"), ... );
Ce qui signifiait que le système de gabarit de Django effectuait toute la logique reverse()
pour moi.
La bonne chose est de supposer que tous les paramètres de JavaScript à Django seront passés en tant que request.GET ou request.POST. Vous pouvez le faire dans la plupart des cas, car vous n'avez pas besoin des URL au format Nice pour les requêtes JavaScript.
Ensuite, le seul problème est de passer l’URL de Django à JavaScript. J'ai publié la bibliothèque pour cela. Exemple de code:
urls.py
def javascript_settings():
return {
'template_preview_url': reverse('template-preview'),
}
javascript
$.ajax({
type: 'POST',
url: configuration['my_rendering_app']['template_preview_url'],
data: { template: 'foo.html' },
});
Semblable à la réponse d'Anatoly, mais un peu plus souple. Mettez en haut de la page:
<script type="text/javascript">
window.myviewURL = '{% url myview foobar %}';
</script>
Ensuite, vous pouvez faire quelque chose comme
url = window.myviewURL.replace('foobar','my_id');
ou peu importe. Si votre URL contient plusieurs variables, exécutez la méthode replace plusieurs fois.
J'aime l'idée d'Anatoly, mais je pense que l'utilisation d'un entier spécifique est dangereuse. Je souhaite généralement spécifier un identifiant d'objet, qui doit toujours être positif. J'utilise donc uniquement des entiers négatifs comme espaces réservés. Cela signifie ajouter -?
à la définition de l'URL, comme suit:
url(r'^events/(?P<event_id>-?\d+)/$', events.views.event_details),
Ensuite, je peux obtenir l’URL inverse dans un modèle en écrivant
{% url 'events.views.event_details' event_id=-1 %}
Et utilisez replace
en javascript pour remplacer l’espace réservé -1
, de sorte que dans le modèle, j’écrirais quelque chose comme:
<script type="text/javascript">
var actual_event_id = 123;
var url = "{% url 'events.views.event_details' event_id=-1 %}".replace('-1', actual_event_id);
</script>
Cela s'étend facilement à plusieurs arguments également, et le mappage d'un argument particulier est visible directement dans le modèle.
J'ai trouvé un truc simple pour cela. Si votre url est un motif tel que:
"xyz/(?P<stuff>.*)$"
et vous souhaitez inverser le JS sans fournir réellement de choses (différer au temps d'exécution du JS pour le fournir) - vous pouvez procéder comme suit:
Modifiez la vue pour attribuer au paramètre une valeur par défaut (aucune) et gérez-la en répondant par une erreur si elle n'est pas définie:
views.py
def xzy(stuff=None):
if not stuff:
raise Http404
... < rest of the view code> ...
"xyz/(?P<stuff>.*)?$"
Et dans le template code js:
.ajax ({ url: "{{url views.xyz}}" + js_stuff, ... ... })
Le modèle généré doit alors avoir l'URL sans le paramètre dans le JS, et vous pouvez simplement concaténer le ou les paramètres.
L'une des solutions que j'ai proposée consiste à générer des URL sur le backend et à les transmettre au navigateur.
Cela peut ne pas convenir dans tous les cas, mais j'ai une table (remplie avec AJAX) et cliquer sur une ligne devrait amener l'utilisateur à la seule entrée de cette table.
(J'utilise Django-restframework et Datatables ).
L'URL est jointe à chaque entrée de AJAX:
class MyObjectSerializer(serializers.ModelSerializer):
url = SerializerMethodField()
# other elements
def get_url(self, obj):
return reverse("get_my_object", args=(obj.id,))
lors du chargement ajax chaque URL est attachée comme attribut de données à la ligne:
var table = $('#my-table').DataTable({
createdRow: function ( row, data, index ) {
$(row).data("url", data["url"])
}
});
et sur click nous utilisons cet attribut de données pour url:
table.on( 'click', 'tbody tr', function () {
window.location.href = $(this).data("url");
} );
Utilisez ce paquet: https://github.com/ierror/Django-js-reverse
Vous aurez un objet dans votre JS avec toutes les URL définies dans Django. C'est la meilleure approche que j'ai trouvée jusqu'à présent.
La seule chose à faire est d’ajouter le js généré dans l’en-tête de votre modèle de base et d’exécuter une commande de gestion pour mettre à jour le js généré chaque fois que vous ajoutez une URL.