Обратные URL-адреса между сайтами Django

Вероятно, простой вопрос, и я просто что-то упускаю, но я застрял в идеях.

У меня есть проект Django, обслуживающий несколько сайтов с sessions.py и совершенно другой ROOT_URLCONFs. Один сайт управляет регистрацией пользователей, настройками аутентификации и профиля, другой сайт (в другом домене) выполняет функции файлового менеджера и так далее. Сайты используют одну и ту же базу данных, медиа и шаблоны. Все сайты используют одну и ту же базу пользователей, реализуя своего рода прозрачный механизм единого входа / единого выхода. Это как один большой сайт, охватывающий несколько доменов.

Проблема в том, что у меня много {% url %} теги в моих шаблонах, и они не работают, когда шаблон используется на других сайтах. И я бы хотел как можно больше избегать жесткого кодирования URL.

Например, на сайте A (a.example.org) у меня есть

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

запись в URL-адресе А. Затем в некоторых global_menu.html шаблон у меня есть {% url list_users %} и, очевидно, это работает отлично, в результате "/users/".

Теперь есть сайт B (b.example.org), который разделяет множество внутренних элементов с A. Чтобы иметь общий внешний вид, я хочу использовать то же самое global_menu.html на сайте Б и хочу {% url list_users %} выводитьhttp://a.example.org/users/". Как лучше всего этого добиться?

В настоящее время я использую отдельные global_menu.html для каждого сайта, но это нарушает принцип СУХОГО и не очень удобно. И да, я использую Джанго contrib.sites рамки с четкими SITE_IDопределены в settings.py для каждого сайта, но пока не использую его где-либо еще.

Обновление: в настоящее время я думаю о переопределении url тег или обезьяна-патчинг reverse(), чтобы вызвать исходный, и для исключений выполнить дополнительный поиск в некотором "списке внешних URI". Если бы уже было что-то подобное - я был бы рад услышать.

Заранее спасибо за ответы!

4 ответа

Решение

Я реализовал это путем переопределения django.core.urlresolvers.reverse с моей пользовательской функцией:

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

Затем перечислить URLconfs в settings.py как это:

ROOT_URLCONF = 'project.urls_a'

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

Да, вам нужно сделать свой собственный {% url %} тег, который использует свой собственный метод обращения.

Например, чтобы выполнить обратное преобразование против site_a urlconf, вы можете использовать такой метод:

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)

Обратная перезапись для Django 1.7.x с использованием тех же настроек из @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

Я поместил код в файл urls.py для запуска при запуске

Я бы предложил сделать два изменения. (1) Переместите шаблоны в общий каталог (а не в приложение), если у вас его еще нет. (2) Изучить недавно добавленную функцию пространств имен URL.

Первое изменение позволит вам иметь общий базовый шаблон и выборочно переопределить его для различных приложений / сайтов. Второй может сделать ваши URL "сухими".

Другие вопросы по тегам