Реверсирование URL-адресов с пространством имен в Django: несколько экземпляров одного и того же приложения - PullRequest
12 голосов
/ 20 ноября 2010

Я работаю с Django некоторое время (в настоящее время на версии 1.2), но совсем недавно начал работать над приложением, которое должно поддерживать несколько экземпляров.Например, файл проекта urls.py будет включать его дважды, в двух разных пространствах имен, например:

urlpatterns = patterns('',
    (r'^instance1/', include('myapp.urls', namespace='instance1')),
    (r'^instance2/', include('myapp.urls', namespace='instance2')),
)

Я шел хорошо, пока не понял, что мне нужно выяснить, что делать со всемивнутренние звонки на reverse() (или шаблон звонков на фильтр {% url %}).Например, предположим, что я делаю что-то вроде следующего в одном из моих представлений:

return HttpResponseRedirect(reverse('view_name'))

или что-то подобное в одном из моих шаблонов:

<a href="{% url view_name %}">link text</a>

...где view_name - это имя шаблона URL, содержащегося в myapp.urls.Поскольку я использую пространства имен, это вызовет ошибку: нет представления с именем view_name.Скорее, я должен сказать это либо instance1:view_name, либо instance2:view_name.Но делать это динамически - это глупо.

Я немного посмотрел, и похоже, что аргумент current_app, переданный либо Context, либо RequestContext, был разработан, чтобы помочь с этим, но это не ясновообще, как динамически передать правильное имя приложения в current_app.Итак, как правильно сообщить Django, какое пространство имен использовать?

РЕДАКТИРОВАТЬ: Мой вариант использования заключается в использовании одной установки приложения несколько раз.То есть он существует на диске только один раз, но включается несколько раз в корень проекта urls.py (каждый раз в другом пространстве имен, как в моем примере выше).Имея это в виду, есть ли какой-нибудь хороший способ отслеживать, из какого пространства имен вызывается представление / шаблон, и использовать какой-либо reverse() или {% url %} флешку в том же пространстве имен?Я знаю, что Django 1.3 предоставит некоторые дополнительные функции, которые могут помочь с этим (а именно, новый и улучшенный resolve()), но, безусловно, есть хороший способ сделать это сейчас ...

Ответы [ 5 ]

4 голосов
/ 02 сентября 2015

Многое изменилось с тех пор, как вопрос был опубликован, но для будущих googlers (как и я) было бы полезно указать, что request имеет пространство имен сейчас (по крайней мере, с 1.7, как показано в в этом примере .

Из того, что я понял, мы могли бы просто передать current_app позиционный аргумент reverse / redirect, но я не смог заставить его работать, поэтому я в итоге создал метод справки дляс этой целью:

def __redirect(request, viewname, *args, **kwargs):
    to = viewname

    if callable(to):
        to = viewname.__module__ + '.' + viewname.__name__
    if request.resolver_match.namespace:
        to = '%s:%s' % (request.resolver_match.namespace, to)

    return redirect(
        to,
        *args,
        **kwargs
    )

Я использую здесь redirect, но все аргументы передаются reverse, так что это то же самое.

3 голосов
/ 14 января 2011

Не очень хорошее решение, но, поскольку вы используете один и тот же текст для своего пространства имен и начальной части пути URL, вы можете извлечь этот элемент из request.path (request.path.split('/')[1]) и установить его как current_app взапросить контекст или просто использовать его в качестве пространства имен в представлениях.

http://docs.djangoproject.com/en/dev/topics/http/urls/#url-namespaces, точка 2.

Вы можете сделать это, например, в процессоре контекста (если вы хотите использоватьпространство имен в шаблоне).

Для представлений вы можете написать декоратор, который передает вашей функции дополнительный kwarg «пространство имен» и использовать его как:

@feed_namespace
def view1(request, *args, **kwargs):
    ns = kwargs['namespace']

или просто написать функцию reverse_namespaced с дополнительным параметром (запрос) откуда функция получает пространство имен и использует его вместо обратного.

Конечно, если вы сделаете это, вам всегда нужно будет использовать путь запроса / пространство имен для этого приложения

2 голосов
/ 20 ноября 2010

Переменная current_app - это то, что вам нужно для себя установить.

Лично я бы рекомендовал установить его на что-то вроде __name__.rsplit('.', 1)[0], чтобы вы получили spam в spam/views.py.

Но вы можете определить, что это все, что вам нравится, если имя вашего приложения соответствует тому, что вы определили в файле urls.

2 голосов
/ 20 ноября 2010

Существует страница с документом об изменении URL-адресов в пространствах имен.

http://docs.djangoproject.com/en/dev/topics/http/urls/#topics-http-reversing-url-namespaces

Либо reverse('instance1:myapp.urls.some_view'), либо reverse('instance1:view_name') должно работать, либо и то и другое :) - я никогда не пробовал это сам.

1 голос
/ 13 января 2011

Если вы не слишком привязаны к пространствам имен, вы можете вместо этого написать свой urls.py следующим образом:

urlpatterns = patterns('',
    (r'^(P<instance>/)', 'controllers.route_me'),
)

Это вызовет функцию controllers.route_me и передаст ей запросплюс строка 'instance', которую вы можете обработать следующим образом:

# (in controllers.py)
def route_me(request, instance):
    # you now have complete control, and do what you need to do with the 'instance' and 'request' vars
    pass
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...