URL inversi tra siti Django
Domanda
Probabilmente una domanda semplice e mi sto perdendo qualcosa, ma sono rimasto senza idee.
Ho un progetto Django che serve diversi siti con sessioni.py
distinti e ROOT_URLCONF
completamente diversi. Un sito gestisce la registrazione dell'utente, le impostazioni di autenticazione e profilo, l'altro sito (su un altro dominio) funge da file manager e così via. I siti condividono lo stesso DB, media e modelli. Tutti i siti condividono la stessa base utenti, implementando una sorta di meccanismo trasparente single sign-on / single-sign-off. È proprio come un grande sito, che si estende su più domini.
Il problema è che ho molti tag {% url%}
nei miei modelli e non funzionano quando il modello viene utilizzato su altri siti. E vorrei evitare il più possibile la codifica degli URL.
Ad esempio, sul sito A (a.example.org) ho un
url('^users/
voce in URLconf di A. Quindi, in alcuni modelli global_menu.html
ho {% url list_users%}
e ovviamente funziona perfettamente, risultando in " / users /
".
Ora c'è il sito B (b.example.org), che condivide molti interni con A. Per avere un aspetto comune, voglio usare lo stesso global_menu.html
sul sito B e vuoi che {% url list_users%}
produca " http://a.example.org/users/
" ;. Qual è il modo migliore per raggiungere questo obiettivo?
Attualmente sto usando un global_menu.html
separato per ciascun sito, ma questo viola il principio DRY e non è molto conveniente. E sì, sto usando il framework contrib.sites
di Django con SITE_ID
definiti in settings.py
per ciascun sito, ma non ancora effettivamente usandolo altrove.
Aggiorna : attualmente sto pensando di reimplementare il tag url
o il patching delle scimmie reverse ()
, per chiamare quello originale, e sulle eccezioni esegui ulteriori ricerche in alcuni "elenchi URI esteri". Se esiste già qualcosa del genere, sarei felice di sentire.
Grazie in anticipo per le risposte!
, 'example.accounts.list_users', name='list_users'),
voce in URLconf di A. Quindi, in alcuni modelli global_menu.html
ho {% url list_users%}
e ovviamente funziona perfettamente, risultando in " / users /
".
Ora c'è il sito B (b.example.org), che condivide molti interni con A. Per avere un aspetto comune, voglio usare lo stesso global_menu.html
sul sito B e vuoi che {% url list_users%}
produca " http://a.example.org/users/
" ;. Qual è il modo migliore per raggiungere questo obiettivo?
Attualmente sto usando un global_menu.html
separato per ciascun sito, ma questo viola il principio DRY e non è molto conveniente. E sì, sto usando il framework contrib.sites
di Django con SITE_ID
definiti in settings.py
per ciascun sito, ma non ancora effettivamente usandolo altrove.
Aggiorna : attualmente sto pensando di reimplementare il tag url
o il patching delle scimmie reverse ()
, per chiamare quello originale, e sulle eccezioni esegui ulteriori ricerche in alcuni "elenchi URI esteri". Se esiste già qualcosa del genere, sarei felice di sentire.
Grazie in anticipo per le risposte!
Soluzione
L'ho implementato sovrascrivendo 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 elencando URLconfs in settings.py
in questo modo:
ROOT_URLCONF = 'project.urls_a'
EXTERNAL_URLCONFS = (
('http://b.example.com/', 'project.urls_b'),
)
Altri suggerimenti
Sì, dovresti creare il tuo tag {% url%}
che utilizza il proprio metodo di inversione.
Ad esempio, per invertire in modo specifico contro urlconf site_a, è possibile 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)
Sovrascrivi al contrario per Django 1.7.x usando le stesse impostazioni di @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 inserito il codice nel file urls.py da eseguire all'avvio
Suggerirei di apportare due modifiche. (1) Sposta i modelli in una directory comune (anziché per applicazione) se non l'hai già fatto. (2) Esamina l'URL appena aggiunto namespace caratteristica.
La prima modifica ti permetterà di avere un modello base comune e di sostituirlo selettivamente per varie app / siti. Il secondo potrebbe servire a rendere i tuoi URL "più asciutti".