2010-04-27 15 views
48

Estoy usando Django en Appengine. Estoy usando la función django reverse() en todas partes, manteniendo todo lo más seco posible.URL SECAS en Django Javascript

Sin embargo, tengo problemas para aplicar esto a mi javascript del lado del cliente. Hay una clase JS que carga algunos datos según una ID aprobada. ¿Existe una forma estándar de no codificar la URL de la que provienen estos datos?

var rq = new Request.HTML({ 
    'update':this.element, 
}).get('/template/'+template_id+'/preview'); //The part that bothers me. 
+1

Me gustaría ver una mayor discusión de esta. Yo también creo que una devolución de llamada en resolución URL es demasiado pesada. ¿Alguien ha encontrado algo más sobre este tema? –

+0

Pregunta similar aquí: http://stackoverflow.com/questions/1795701/django-reverse-for-javascript –

+0

Extraño No encontré eso en el momento en que publiqué el mío. Tampoco tiene respuestas satisfactorias, aunque je. – noio

Respuesta

8

La solución más razonable parece estar pasando una lista de URL en un archivo JavaScript, y que tiene un equivalente de JavaScript inversa() disponible en el cliente. La única objeción podría ser que toda la estructura de URL está expuesta.

Aquí está tal function (de este question).

4

Lo bueno es suponer que todos los parámetros de JavaScript a Django se pasarán como request.GET o request.POST. Puede hacerlo en la mayoría de los casos, porque no necesita urls con formato agradable para consultas de JavaScript.

Entonces, el único problema es pasar la URL de Django a JavaScript. He publicado una biblioteca para eso. Código de ejemplo:

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' }, 
}); 
28

Hay otro método, que no requiere la exposición de toda la estructura url o ajax solicitudes para la resolución de cada url. Si bien no es muy bonito, es mejor que los demás con sencillez:

var url = '{% url blog_view_post 999 %}'.replace (999, post_id); 

(blog_view_post URLs no deben contener la magia 999 número de ellos, por supuesto.)

+7

He estado haciendo esto y me he sentido un poco sucio, pero verlo aquí me hace sentir un poquito mejor al respecto. –

+0

Tenga en cuenta los tipos de caracteres esperados para el parámetro de URL. Si el parámetro de URL acepta dígitos esto funciona, pero no si solo espera letras. También sugeriría usar algunos 000, ya que no debería existir (para un object.id, al menos) – jpimentel

+1

Esto está sucio. Si vas a usar la url en javascript, mejor para que acepte los parámetros GET y luego no necesites reemplazarla. GET ha sido un estándar para las edades y todos los marcos de JavaScript admiten el paso de una estructura de datos que se convertirá en parámetros (escapó correctamente también a diferencia de esto) y se leerá mejor. – dalore

4

Similar a la respuesta de Anatoly, pero un poco más flexible. Puso en la parte superior de la página:

<script type="text/javascript"> 
window.myviewURL = '{% url myview foobar %}'; 
</script> 

entonces usted puede hacer algo como

url = window.myviewURL.replace('foobar','my_id'); 

o lo que sea. Si su url contiene múltiples variables, simplemente ejecute el método de reemplazo varias veces.

1

He encontrado un truco simple para esto. Si su URL es un patrón como:

"xyz/(?P<stuff>.*)$" 

y desea invertir en el JS sin tener que proporcionar cosas (dejando a salvo el tiempo de JS ejecución para proporcionar este) - se puede hacer lo siguiente:

Alter la vista para dar al parámetro un valor predeterminado - de ninguno, y manejarlo respondiendo con un error si no está configurado:

vistas.py

def xzy(stuff=None): 
    if not stuff: 
    raise Http404 
    ... < rest of the view code> ... 
  • Alter partido URL para hacer que el parámetro opcional: "xyz/(?P<stuff>.*)?$"
  • Y en el código de la plantilla JS:

    .ajax ({ url: "{{url vistas. xyz}}" + js_stuff, ... ... })

La plantilla generada debería tener la URL sin el parámetro en el JS, y en el JS simplemente puede concatenar en los parámetros.

2

Me gusta la idea de Anatoly, pero creo que usar un número entero específico es peligroso. Por lo general, quiero especificar un ID de objeto, que siempre se requiere que sea positivo, así que solo uso enteros negativos como marcadores de posición. Esto significa añadir -? a la de la definición url, así:

url(r'^events/(?P<event_id>-?\d+)/$', events.views.event_details), 

entonces puedo obtener la URL inversa en una plantilla escribiendo

{% url 'events.views.event_details' event_id=-1 %} 

Y el uso de replace en javascript para reemplazar el marcador de posición -1, para que en la plantilla escribiera algo como

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

Esto se extiende fácilmente a múltiples argumentos para o, y el mapeo de un argumento particular es visible directamente en la plantilla.

+0

En realidad, creo que esto es mucho más peligroso ... 1) Las ID negativas ahora están permitidas en la URL, lo que significa que se pueden pasar en tu vista; Necesitará una lógica adicional para comprobarlo. 2) Es mucho más probable que aparezca "-1" en la URL como parte de la cadena estática que "999". La razón por la que "999" funciona es porque no hay nada más en la parte estática de la URL que en realidad sea "999". No importa que sea una identificación válida, siempre que sea reemplazada sin ambigüedad. – user193130

+1

@ user193130 Si es una ID de objeto, probablemente debería usar 'get_object_or_404' de todos modos: el usuario final verá la misma 404 como si el patrón de URL no aceptara el negativo – Izkata

0

Una de las soluciones con las que llegué es la de generar URL en el back-end y pasarlas al navegador de alguna manera.

Puede que no sea adecuado en todos los casos, pero tengo una tabla (llena con AJAX) y al hacer clic en una fila debería llevar al usuario a la entrada única de esta tabla.

(Estoy usando django-restframework y Datatables).

Cada entrada de AJAX tiene la url adjunto:

class MyObjectSerializer(serializers.ModelSerializer): 
    url = SerializerMethodField() 
    # other elements 

    def get_url(self, obj): 
     return reverse("get_my_object", args=(obj.id,)) 

en ajax carga cada URL se adjunta como atributo de datos a la fila:

var table = $('#my-table').DataTable({ 
    createdRow: function (row, data, index) { 
     $(row).data("url", data["url"]) 
    } 
}); 

y el clic que utilizan este atributo de datos de URL :

table.on('click', 'tbody tr', function() { 
    window.location.href = $(this).data("url"); 
}); 
8

Habiendo luchado con esto, se me ocurrió una solución ligeramente diferente.

En mi caso, quería un script JS externo para invocar una llamada AJAX con un clic de botón (después de hacer algún otro procesamiento).

En el HTML, que utiliza un archivo HTML-5 atributo personalizado tanto

<button ... id="test-button" data-ajax-target="{% url 'named-url' %}"> 

Luego, en el javascript, simplemente hizo

$.post($("#test-button").attr("data-ajax-target"), ...); 

que significaba sistema de plantillas de Django hizo toda la lógica reverse() de yo.

+0

+1 Este es el enfoque que estaba considerando antes de buscar por lo que todos los demás estaban haciendo. Parece la solución ideal para mí, a menos que el soporte heredado sea un problema. No estoy seguro de por qué no tiene más tracción aquí. – oogles

+0

Esto es realmente simple y tu ejemplo fue exactamente lo que estaba tratando de hacer – 5uperdan

0

utilizar este paquete: https://github.com/ierror/django-js-reverse

Vas a tener un objeto en sus JS con todas las direcciones URL definidas en Django. Es el mejor enfoque que he encontrado hasta ahora.

La única cosa que hay que hacer es añadir el js generados en la cabecera de la plantilla base y ejecutar un comando de gestión para actualizar los js generados cada vez que se agrega una URL