web-dev-qa-db-fra.com

DRY URL dans Django Javascript

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.
48
noio

La solution la plus raisonnable semble être de passer une liste d'URL dans un fichier JavaScript et d'avoir un équivalent JavaScript de reverse () disponible sur le client. La seule objection peut être que toute la structure de l'URL est exposée. 

Voici une telle fonction (de cette question ).

8
noio

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.)

29
Anatoly Rr

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.

8
kdopen

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' },
});
4
Tomasz Wysocki

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.

4
Hilton Shumway

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.

2
leifdenby

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> ...
  • Modifiez la correspondance d'URL pour rendre le paramètre facultatif: "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.

1
Danny Staple

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");
} );
0
Pax0r

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.

0
Karim N Gorjux