2009-08-03 13 views
8

Probablemente es una pregunta simple y me falta algo, pero no tengo ideas.Django URLs inversas entre sitios

Tengo el proyecto Django que sirve varios sitios con distinto sessions.py y completamente diferente ROOT_URLCONF s. Un sitio maneja el registro del usuario, la autenticación y la configuración del perfil, otro sitio (en otro dominio) actúa como administrador de archivos, y así sucesivamente. Los sitios comparten la misma base de datos, medios y plantillas. Todos los sitios comparten la misma base de usuarios, implementando un tipo de mecanismo transparente de inicio de sesión único/inicio de sesión único. Es como un gran sitio que abarca varios dominios.

El problema es que tengo muchas etiquetas {% url %} en mis plantillas, y no funcionan cuando la plantilla se usa en otros sitios. Y me gustaría evitar las URL de codificación dura tanto como sea posible.

Por ejemplo, en el sitio A (a.example.org) que tienen una entrada

url('^users/$', 'example.accounts.list_users', name='list_users'), 

en una de URLconf. Entonces, en alguna plantilla global_menu.html tengo {% url list_users %} y obviamente funciona perfectamente, lo que resulta en "/users/".

Ahora, hay sitio B (b.example.org), que comparten una gran cantidad de elementos internos con A. Tener común look-and-feel quiero usar la misma global_menu.html en el sitio B y quiero {% url list_users %} a la salida "http://a.example.org/users/ ". ¿Cuál es la mejor manera de lograr esto?

Actualmente, estoy usando global_menu.html por separado para cada sitio, pero esto viola el principio DRY, y no es realmente conveniente. Y, sí, estoy usando el framework contrib.sites de Django con distintos SITE_ID definidos en settings.py para cada sitio, pero que aún no lo estoy usando en ningún otro lado.

actualización: Actualmente estoy pensando en reimplementar url etiqueta o mono-parches reverse(), para llamar a la original, y sobre las excepciones realizan adicional mirar hacia arriba en alguna "extraña lista de URI". Si ya existe algo como esto, me gustaría escucharlo.

¡Gracias de antemano por las respuestas!

Respuesta

12

vez implementado anulando django.core.urlresolvers.reverse con mi función personalizada:

from django.core import urlresolvers 
from django.conf import settings 

__real_reverse = urlresolvers.reverse 

def reverse(viewname, urlconf=None, args=None, kwargs=None, prefix=None): 
    try: 
     return __real_reverse(viewname, urlconf, args, kwargs, prefix) 
    except urlresolvers.NoReverseMatch, no_match: 
     external_urlconfs = getattr(settings, 'EXTERNAL_URLCONFS', []) 
     for p, c in external_urlconfs: 
      c = urlresolvers.RegexURLResolver(r'^/', c) 
      try: 
       return p + c.reverse(viewname, *args, **kwargs) 
      except urlresolvers.NoReverseMatch: 
       pass 
     raise no_match 

urlresolvers.reverse = reverse 

A continuación, enumerar URLconfs en settings.py de esta manera:

ROOT_URLCONF = 'project.urls_a' 

EXTERNAL_URLCONFS = (
    ('http://b.example.com/', 'project.urls_b'), 
) 
0

Sugeriría hacer dos cambios. (1) Mueva las plantillas a un directorio común (en lugar de por aplicación) si ya no lo tiene. (2) Investigue la función URL recientemente agregado namespaces.

El primer cambio le permitirá tener una plantilla base común y anularla selectivamente para varias aplicaciones/sitios. El segundo podría servir para hacer sus URL "más secas".

+0

(1) ya está hecho. (2) es una función elegante, gracias por señalarlo, pero no ayuda mucho con las URL con nombres inexistentes. Intenté agregar algo como 'url ('http: \/\/a \ .example \ .com/users /', lambda r: None, name = 'list_users')' a B's URLconf, pero no funciona t trabajo como esperaba (devuelve "/ http: ..."). – drdaeman

2

Sí, necesitaría hacer su propia etiqueta {% url %} que utiliza su propio método de inversión.

Por ejemplo, para invertir específicamente contra la URLconf Sitio_A continuación, se puede utilizar un método como este:

from django.core.urlresolvers import reverse 
import site_a 

def site_a_reverse(viewname, args=None, kwargs=None): 
    # If your sites share the same database, you could get prefix from Site.objects.get(pk=site_a.settings.SITE_ID) 
    prefix = 'http://a.example.com/' # Note, you need the trailing slash 
    reverse(viewname, urlconf=site_a.urls, args=args, kwargs=kwargs, prefix=prefix) 
+0

¡Gracias! Terminé el parche de mono 'reverse()' (pongo mi propio código en una respuesta separada). – drdaeman

1

sobrescribir inversa para Django 1.7.x utilizando la misma configuración de @drdaeman

# -*- coding: utf-8 -*- 
from django.core import urlresolvers 
from django.conf import settings 

__real_reverse = urlresolvers.reverse 


def reverse(viewname, urlconf=None, args=None, kwargs=None, prefix=None, current_app=None): 
    try: 
     return __real_reverse(viewname, urlconf, args, kwargs, prefix, current_app) 
    except urlresolvers.NoReverseMatch, no_match: 
     external_urlconfs = getattr(settings, 'EXTERNAL_URLCONFS', []) 
     for p, c in external_urlconfs: 
      urlconf = c 
      try: 
       return p + __real_reverse(viewname, urlconf, args, kwargs, prefix, current_app) 
      except urlresolvers.NoReverseMatch: 
       pass 
     raise no_match 

urlresolvers.reverse = reverse 

coloqué el código en el archivo urls.py para ejecutar en el arranque

Cuestiones relacionadas