web-dev-qa-db-fra.com

Comment utilisez-vous les espaces de noms URL Django?

J'essaie de comprendre les espaces de noms d'URL Django . Mais je ne trouve aucun exemple ou documentation.

Voici ce que j'ai essayé.

urls.py:

from Django.conf.urls.defaults import *

urlpatterns = patterns('',
    (r'^foo/', include('sub_urls', namespace='foo', app_name='foo')),
    (r'^bar/', include('sub_urls', namespace='bar', app_name='bar')),            
)

sub_urls.py:

from Django.conf.urls.defaults import patterns, url
from views import view1

urlpatterns = patterns('views',
    url(r'^(?P<view_id>\d+)/$', view1, name='view1')
)

views.py:

from Django.shortcuts import render_to_response

def view1(request, view_id):
    return render_to_response('view1.html', locals())

Dans view1.html, {% url foo: view1 3%} sorties/foo/3 et {% url bar: view1 3%} sorties/bar/3. Cela est vrai que je navigue vers/foo/X ou/bar/X.

Ce que je veux, c'est pouvoir accéder à/foo/X ou/bar/X, et avoir {% url view1 3%} le résultat final soit/foo/3 ou/bar/3, respectivement.

29
Chase Seibert

Je pense que ce n'est pas possible à Django pour le moment. Jetez un coup d’œil à/ Message du forum qui fait référence Ticket 11559 . Je pense que vous essayez de faire la même chose: transmettre efficacement un paramètre implicite à la balise URL. 

En outre, en supposant que sub_urls provient de la même application les deux fois, vous devez vous assurer que app_name est identique dans les deux cas. Vous ne devriez avoir besoin que de changer d'espace de nom.

3
Mystic

Il semble n'y avoir aucun moyen direct de le faire. Je voudrais utiliser une solution similaire à celle que vous avez introduite en utilisant une balise de modèle, bien que j'ai trouvé une manière plus générique. J'ai utilisé le fait que vous pouvez passer des paramètres optionnels dans votre conf url, afin que vous puissiez garder une trace de l'espace de noms:

#urls.py
from Django.conf.urls import defaults

urlpatterns = defaults.patterns('',
    defaults.url(r'^foo/', include('sub_urls', namespace='foo', app_name='myapp'), 
    kwargs={'namespace':'foo'}),
    defaults.url(r'^bar/', include('sub_urls', namespace='bar', app_name='myapp'),
    kwargs={'namespace':'bar'}),      
)

Cela viole également le principe DRY, mais pas beaucoup :)

Ensuite, dans votre vue, vous obtenez la variable d'espace de nom (sub_urls.py serait identique):

#views.py
from Django import shortcuts

def myvew(request, namespace):
    context = dict(namespace=namespace)
    return shortcuts.render_to_response('mytemplate.html', context)

Plus tard, vous avez juste besoin d’une simple balise à laquelle vous transmettez votre variable d’espace de nom et votre nom de vue:

#tags.py
from Django import template
from Django.core import urlresolvers

register = template.Library()

def namespace_url(namespace, view_name):
   return urlresolvers.reverse('%s:%s' % (namespace, view_name, args=args, kwargs=kwargs)))
register.simple_tag(namespace_url)

et utilisez-le dans le modèle (assurez-vous de transmettre votre nom de vue en tant que chaîne et non en tant que variable de modèle):

<!-- mytemplate.html -->
{% load tags %}
{% namespace_url namespace "view1"%}

Merci pour votre suggestion, btw .. Je cherchais qc. comme ça.

6
Torsten Engelbrecht

Voici une solution que je suis venu avec.

views.py:

from Django.shortcuts import render_to_response
from Django.template import RequestContext

def render_response_context(view, locals):
    request = locals["request"]
    app = "bar" if request.META["PATH_INFO"].lower().startswith("/bar") else "foo"
    return render_to_response(view, locals, 
        context_instance=RequestContext(request, current_app=app))

def view1(request, view_id):    
    return render_response_context('view1.html', locals())

view1.html:

{% load extras %}
{% namespace_url view1 3 %}

extras.py:

from Django import template
from Django.core.urlresolvers import reverse

register = template.Library()

@register.tag
def namespace_url(parser, token):
    tag_name, view_string, arg1 = token.split_contents()
    return NamespaceUrlNode(view_string, arg1)

class NamespaceUrlNode(template.Node):
    def __init__(self, view_string, arg1):
        self.view_string = view_string
        self.arg1 = arg1
    def render(self, context):
        return reverse("%s:%s" % (context.current_app, self.view_string), args=[self.arg1])

En gros, je me suis assuré de toujours passer le contexte current_app sous la forme "foo" ou "bar", que je calcule manuellement en regardant l'URL de la requête. Ensuite, j'utilise une balise personnalisée qui résout une URL basée sur current_app.

Ce n'est pas très générique; "foo" et "bar" sont codés en dur, et la balise ne peut prendre qu'un seul argument. Même avec ces problèmes résolus, cela semble être un hack.

0
Chase Seibert

Je me rends compte que la solution ci-dessous viole le principe DRY, car vous devez créer essentiellement des fichiers de configuration d'URL en double pour foo et bar, mais je pense que cela devrait fonctionner.

urls.py:

from Django.conf.urls.defaults import *

urlpatterns = patterns('',
    (r'^foo/', include('sub_urls_foo')),
    (r'^bar/', include('sub_urls_bar')),            
)

sub_urls_foo.py:

from Django.conf.urls.defaults import patterns, url
from views import view1

urlpatterns = patterns('views',
    url(r'^(?P<view_id>\d+)/$', view1, 'view1_foo', {'namespace': 'view1_foo'})
)

sub_urls_bar.py:

from Django.conf.urls.defaults import patterns, url
from views import view1

urlpatterns = patterns('views',
    url(r'^(?P<view_id>\d+)/$', view1, 'view1_bar', {'namespace': 'view1_bar'})
)

views.py:

from Django.shortcuts import render_to_response

def view1(request, view_id, namespace):
    return render_to_response('view1.html', locals())

Et puis, pour le modèle, utilisez ceci:

{% url namespace 3 %}

Je n'ai pas testé l'idée d'utiliser une variable dans la section name de la balise {% url%}, mais je pense que cela devrait fonctionner.

0
Steven Potter