2009-08-03 13 views
8

Probabilmente semplice domanda inversa e sto solo perdendo qualcosa, ma mi sono bloccato a corto di idee.Django cross-site URL

Ho un progetto Django che serve diversi siti con distinto sessions.py e completamente diverso ROOT_URLCONF s. Un sito gestisce le impostazioni di registrazione, autenticazione e profilo degli utenti, altri siti (su un altro dominio) agiscono come file manager e così via. I siti condividono lo stesso DB, i media e i modelli. Tutti i siti condividono la stessa base di utenti, implementando una sorta di meccanismo trasparente single-sign-on/single-sign-off. È proprio come un grande sito, che si estende su diversi domini.

Il problema è che ho un sacco di tag {% url %} nei miei modelli e non funzionano quando i modelli vengono utilizzati su altri siti. E vorrei evitare il più possibile gli URL hardcoding.

Per esempio, sul sito A (a.example.org) Ho una voce

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

in Un URLconf. Poi, in qualche global_menu.html modello ho {% url list_users %} e, ovviamente, funziona perfettamente, con conseguente "/users/".

Ora, non c'è sito B (b.example.org), la condivisione di un sacco di interni con A. Per avere comuni look-and-feel voglio usare lo stesso global_menu.html sul sito B e voglio {% url list_users %} di uscita "http://a.example.org/users/ ". Qual è il modo migliore per ottenerlo?

Attualmente, sto utilizzando il numero global_menu.html separato per ciascun sito, ma questo viola il principio ASCIUTTO e non molto comodo. E, sì, sto utilizzando il framework di Django contrib.sites con distinte SITE_ID s definiti settings.py per ogni sito, ma non ancora effettivamente usarlo in qualsiasi altro luogo.

Aggiornamento: Attualmente sto pensando di reimplementare url tag o scimmia-patching reverse(), chiamare quello originale, e sulle eccezioni eseguire ulteriore sguardo in qualche "lista URI straniero". Se esiste già qualcosa di simile, sarei felice di sentirlo.

Grazie in anticipo per le risposte!

risposta

12

Ho implementato lo ridefinendo django.core.urlresolvers.reverse con la mia funzione personalizzata:

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 

Quindi elencare URLconfs in in questo modo:

ROOT_URLCONF = 'project.urls_a' 

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

Vorrei suggerire fare due modifiche. (1) Sposta i modelli in una directory comune (piuttosto che per applicazione) se non lo hai già fatto. (2) Esaminare la funzionalità URL namespaces appena aggiunta.

Il primo cambiamento vi permetterà di avere un modello di base comune e selettivamente ignorare per varie applicazioni/siti. Il secondo potrebbe servire a rendere i tuoi URL "più asciutti".

+0

(1) è già fatto. (2) è una caratteristica di fantasia, grazie per aver segnalato, ma non aiuta molto per gli URL con nome inesistenti. Ho provato ad aggiungere qualcosa come 'url ('http: \/\/a \ .example \ .com/users /', lambda r: None, name = 'list_users')' a B's URLconf, ma non lo fa lavoro come mi aspetterei (restituisce "/ http: ..."). – drdaeman

2

Sì, è necessario creare il proprio tag {% url %} che utilizza il proprio metodo di inversione.

Ad esempio, per invertire specificamente contro l'urlconf site_a allora si potrebbe utilizzare un metodo come questo:

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

Grazie! Ho finito con la patch delle scimmie 'reverse()' (inserire il mio codice in una risposta separata). – drdaeman

1

inversione sovrascrivere per Django 1.7.x utilizzando le stesse impostazioni da @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 

ho messo il codice nel file urls.py da eseguire all'avvio