2009-12-17 11 views
28

J'essaie d'obtenir le coup de Django URL namespaces. Mais je ne trouve aucun exemple ou document.Comment utilisez-vous les espaces de noms d'URL Django?

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

En 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 naviguer jusqu'à/foo/X ou/bar/X, et avoir {% url view1 3%} en sortie soit/foo/3 ou/bar/3, respectivement.

+0

La raison pour laquelle je fais cela est que je peux avoir les deux espaces de noms utilisent des fichiers CSS différents. C'est à dire. La navigation sous/foo inclurait foo.css, et/bar inclurait bar.css. –

+0

Je serais conscient que d'avoir des URL différentes avec le même contenu va certainement pénaliser votre site sur les moteurs de recherche. Je ne sais pas si cela vous préoccupe ou non, mais si c'est le cas, je recommanderais de contourner ce problème d'une autre façon. Peut-être que vous pourriez définir un cookie sur le client et laissez-les choisir les styles CSS d'une autre manière. – Clueless

+0

J'ai fini par définir le CSS en fonction de différents sous-domaines. C'est juste une douleur à tester localement, ce qui nécessite des entrées de fichier hôte. –

Répondre

3

Je pense que ce n'est pas possible dans django en ce moment. Jetez un oeil à ce message board post qui référence Ticket 11559.Je pense que vous essayez de faire la même chose - passez effectivement un paramètre implicite à la balise URL.

En outre, en supposant que sub_urls est de la même application les deux fois, vous devez vous assurer que app_name est le même dans les deux cas. Vous devriez seulement devoir changer l'espace de noms.

0

Voici une solution que j'ai trouvée.

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 fait, je me suis assuré de toujours passer le contexte de CURRENT_APP que ce soit " 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 le tag ne peut prendre qu'un seul argument. Même avec ces problèmes résolus, cela semble être un hack.

0

Je réalise que la solution ci-dessous viole le principal DRY car vous devez créer essentiellement des fichiers de configuration d'url en double pour foo et la barre, 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 utiliser:

{% url namespace 3 %} 

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

+0

Vous devriez donc utiliser {% url view1_bar 3%} ou {% url view1_foo 3%}? Ce que je veux vraiment, c'est être capable d'utiliser {% url view1 3%}, et de choisir foo ou bar en fonction de l'espace de noms qui correspond à l'URL actuelle. –

+0

Votre droite, mon exemple ne fonctionnera pas. Je l'ai construit sous l'hypothèse que je pourrais passer une variable de modèle à la balise {% url%}. Ce que j'ai maintenant lu n'est pas le cas. Donc, cela vous laisse deux options. Traitez l'url dans votre vue en utilisant reverse() et passez-le dans le contexte du template, ou créez un tag de template personnalisé. –

5

Il semble n'y avoir aucun moyen direct de le faire. J'utiliserais une solution similaire à celle que vous avez introduite en utilisant une balise template, même si j'ai trouvé un moyen plus générique. J'ai utilisé le fait que vous pouvez passer des paramètres facultatifs dans votre conf url, de sorte que vous pouvez 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'}),  
) 

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

Puis, en votre point de vue que vous obtenez la variable d'espace de noms (sub_urls.py serait le même):

#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 que vous passez votre variable d'espace de noms et le 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 de l'utiliser dans le modèle (assurez-vous de passer votre nom de vue comme une chaîne, et non comme une variable de modèle):

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

Merci pour votre indice btw .. Je cherchais STH. comme ça.

+0

Je vois que c'est un très vieux post, cependant, dict (namespace = namespace) est plus coûteux en calcul que {'namespace': namespace}. Utilisez 'dis' pour savoir pourquoi! – explodes

+0

Petite modification de la fonction namespace_url: def namespace_url (espace de noms, nom_vue, * args, ** kwargs): return urlresolvers.reverse ('% s:% s'% (espace de noms, nom_vue), args = args, kwargs = kwargs) Permet de prendre en charge les paramètres d'URL – georgerw

+0

Thx. Belle addition. Ajouté à la réponse. –