URL-адреси django без косої риски не переспрямовують


89

У мене є дві програми, розташовані на двох окремих комп’ютерах. На комп'ютері A у urls.pyфайлі у мене є такий рядок:

(r'^cast/$', 'mySite.simulate.views.cast')

І що URL буде працювати як mySite.com/cast/і mySite.com/cast. Але на комп’ютерній BI має подібну URL-адресу, виписану на зразок:

(r'^login/$', 'mySite.myUser.views.login')

З якихось причин на комп’ютері B url mySite.com/login/ буде працювати, але mySite.com/loginзависне і не буде спрямовувати назад, mySite.com/login/як це буде на комп’ютері A. Чи є щось, що я пропустив? Обидва url.pyфайли виглядають ідентично мені.

Відповіді:


103

перевірте APPEND_SLASHналаштування у файлі settings.py

більше інформації в документації django


4
"Якщо встановлено значення" True ", якщо URL-адреса запиту не відповідає жодному з шаблонів URLconf і не закінчується косою рисою, HTTP-переспрямування видається на ту саму URL-адресу з доданою косою рисою. Зверніть увагу, що переспрямування може спричинити будь-які дані, подані в запиті POST, будуть втрачені. " "Параметр APPEND_SLASH використовується, лише якщо встановлено CommonMiddleware ...". Я віддаю перевагу відповіді Майкла Гендіна за більш чисте рішення.
Wtower

3
Це не спрацьовує, якщо ви використовуєте додаткову URL-адресу "зловити все" при останньому введенні ваших шаблонів url. Відповідь @ speedplane спрацює навіть у таких ситуаціях. Але, звичайно, це простіше, і його слід використовувати, якщо немає записів urlpattern "спіймати усіх".
np8

194

Або ви можете написати свої URL-адреси так:

(r'^login/?$', 'mySite.myUser.views.login')

Знак питання після косої риски робить його необов’язковим у регулярному виразі. Використовуйте його, якщо з якихось причин ви не хочете використовувати налаштування APPEND_SLASH.


12
Називайте мене наївним - але чому ця відповідь не отримала мільйон голосів проти і запис у django faq?
Фергал Моран

42
Практично впевнений, що ви не хочете робити це з міркувань SEO - краще перенаправити на канонічну URL-адресу, ніж мати дві дійсні URL-адреси.
Брайан Франц,

47
Якщо ви створюєте RESTful API за допомогою Django, це може бути хорошим рішенням, коли розробники POST дані безпосередньо до кінцевої URL-адреси. При використанні APPEND_SLASH, якщо вони випадково надіслали його без кінцевої косої риски, а ваш urlconf має ЗАКІНЧИЙ слеш, вони отримають виняток про втрату даних при перенаправленні запитів POST.
OrPo

5
Проблема з цим рішенням полягає в тому, що ви обслуговуєте одну і ту ж сторінку з 2-ма URL-адресами (з припущенням і без нього /) - неакуратний, поганий для сканерів, складніший в обслуговуванні, складніший перехід на нову систему (оскільки так легко не помітити)
Jiaaro

Гарна відповідь. Я волів би заборонити скісну риску (оскільки вона означала початок чогось нового, а не кінець чогось (наприклад, / і т.д.), але це дозволяє використовувати стандартний (/ view) та нестандартний (/ view /).
Девід Бец,

19

Це покращує відповідь @Michael Gendin. Його відповідь подає однакову сторінку з двома окремими URL-адресами. Було б краще мати loginавтоматичне перенаправлення на login/, а потім подати останню як головну сторінку:

from django.conf.urls import patterns
from django.views.generic import RedirectView

urlpatterns = patterns('',
    # Redirect login to login/
    (r'^login$', RedirectView.as_view(url = '/login/')),
    # Handle the page with the slash.
    (r'^login/', "views.my_handler"),
)

Дуже корисно, коли у вас є загальнодоступна URL-адреса в кінці.
thclark,

Як це могло працювати з регулярними виразами? Якщо оригінальна URL-адреса відповідає регулярному виразу з іменем клієнта, наприклад
Ніколо Гаспаріні

@ NicolòGasparini - новіші версії Django мають pattern_nameаргумент, який використовується redirectразом із усіма відповідними аргументами url.
Тім Тісдалл

2

У мене теж була така сама проблема. Моє рішення було поставлено (| /) перед кінцевим рядком мого регулярного виразу.

url(r'^artists/(?P[\d]+)(|/)$', ArtistDetailView.as_view()),


1

Додайте скісну риску без перенаправлення , використовуйте її замість CommonMiddleware у налаштуваннях, Django 2.1:

MIDDLEWARE = [
    ...
    # 'django.middleware.common.CommonMiddleware',
    'htx.middleware.CommonMiddlewareAppendSlashWithoutRedirect',
    ...
]

Додайте до свого основного каталогу додатків middleware.py :

from django.http import HttpResponsePermanentRedirect, HttpRequest
from django.core.handlers.base import BaseHandler
from django.middleware.common import CommonMiddleware
from django.conf import settings


class HttpSmartRedirectResponse(HttpResponsePermanentRedirect):
    pass


class CommonMiddlewareAppendSlashWithoutRedirect(CommonMiddleware):
    """ This class converts HttpSmartRedirectResponse to the common response
        of Django view, without redirect.
    """
    response_redirect_class = HttpSmartRedirectResponse

    def __init__(self, *args, **kwargs):
        # create django request resolver
        self.handler = BaseHandler()

        # prevent recursive includes
        old = settings.MIDDLEWARE
        name = self.__module__ + '.' + self.__class__.__name__
        settings.MIDDLEWARE = [i for i in settings.MIDDLEWARE if i != name]

        self.handler.load_middleware()

        settings.MIDDLEWARE = old
        super(CommonMiddlewareAppendSlashWithoutRedirect, self).__init__(*args, **kwargs)

    def process_response(self, request, response):
        response = super(CommonMiddlewareAppendSlashWithoutRedirect, self).process_response(request, response)

        if isinstance(response, HttpSmartRedirectResponse):
            if not request.path.endswith('/'):
                request.path = request.path + '/'
            # we don't need query string in path_info because it's in request.GET already
            request.path_info = request.path
            response = self.handler.get_response(request)

        return response

0

У мене була та сама проблема. У моєму випадку це був застарілий залишок старої версії в urls.py від до staticfiles:

url(r'^%s(?P<path>.*)$' % settings.MEDIA_URL.lstrip('/'),
    'django.views.static.serve',
    kwargs={'document_root': settings.MEDIA_ROOT}),

MEDIA_URL було порожнім, тому цей шаблон відповідав усьому.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.