Django-URLs ohne abschließenden Schrägstrich werden nicht umgeleitet


86

Ich habe zwei Anwendungen auf zwei separaten Computern. Auf Computer A habe urls.pyich in der Datei eine Zeile wie die folgende:

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

Und diese URL funktioniert sowohl für mySite.com/cast/als auch mySite.com/cast. Aber auf Computer BI haben Sie eine ähnliche URL geschrieben wie:

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

Aus irgendeinem Grund url mySite.com/loginfunktioniert das / auf Computer B , mySite.com/loginhängt aber und wird nicht zurückgeleitet, mySite.com/login/wie es auf Computer A der Fall ist. Gibt es etwas, das ich verpasst habe? Beide url.pyDateien sehen für mich identisch aus.

Antworten:


101

Überprüfen Sie Ihre APPEND_SLASHEinstellung in der Datei settings.py

Weitere Infos in den Django-Dokumenten


4
"Wenn die Anforderungs-URL auf True gesetzt ist und mit keinem der Muster in der URLconf übereinstimmt und nicht mit einem Schrägstrich endet, wird eine HTTP-Umleitung an dieselbe URL mit einem angehängten Schrägstrich ausgegeben. Beachten Sie, dass die Umleitung dazu führen kann Alle in einer POST-Anfrage übermittelten Daten gehen verloren. " "Die Einstellung APPEND_SLASH wird nur verwendet, wenn CommonMiddleware installiert ist ...". Ich bevorzuge Michael Gendins Antwort für eine sauberere Lösung.
— Wtower

2
Dies funktioniert nicht, wenn Sie beim letzten Eintrag Ihrer URL-Muster eine zusätzliche URL "Alle abfangen" verwenden. Die Antwort von @ speedplane funktioniert auch in diesen Situationen. Dies ist natürlich einfacher und sollte verwendet werden, wenn keine URL-Mustereinträge "Alle abfangen" vorhanden sind.
— np8

192

Oder Sie können Ihre URLs folgendermaßen schreiben:

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

Das Fragezeichen nach dem abschließenden Schrägstrich macht es in regulärem Ausdruck optional. Verwenden Sie diese Option, wenn Sie aus bestimmten Gründen die Einstellung APPEND_SLASH nicht verwenden möchten.


11
Nennen Sie mich naiv - aber warum hat diese Antwort nicht eine Million positive Stimmen und einen Eintrag in der Django-FAQ?
— Fergal Moran

41
Ich bin mir ziemlich sicher, dass Sie dies aus SEO-Gründen nicht tun möchten - es ist besser, zu einer kanonischen URL umzuleiten, als zwei gültige URLs zu haben.
— Brian Frantz

46
Wenn Sie eine RESTful-API mit Django erstellen, kann dies eine gute Lösung sein, wenn Entwickler Daten direkt an die Endpunkt-URL senden. Wenn sie es verwenden APPEND_SLASH, wenn sie es versehentlich ohne abschließenden Schrägstrich gesendet haben und Ihre urlconf MIT einem abschließenden Schrägstrich ist, erhalten sie eine Ausnahme über Datenverluste, wenn sie POST-Anforderungen umleiten.
— OrPo

5
Das Problem bei dieser Lösung ist, dass Sie dieselbe Seite unter 2 URLs (mit und ohne Trailing /) bereitstellen - schlampig, schlecht für Crawler, schwieriger zu warten, schwieriger auf ein neues System zu migrieren (da es so leicht zu übersehen ist)
— Jiaaro

Gute Antwort. Ich würde es vorziehen, den Schrägstrich nicht zuzulassen (da dies den Beginn von etwas Neuem bedeutet, nicht das Ende von etwas (z. B. / etc), aber dies ermöglicht den Standard (/ view) und den Nicht-Standard (/ view /).
— David Betz

18

Dies verbessert die Antwort von @Michael Gendin. Seine Antwort dient der identischen Seite mit zwei separaten URLs. Es wäre besser, loginautomatisch umzuleiten login/und diese dann als Hauptseite zu verwenden:

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"),
)

Sehr nützlich, wenn Sie am Ende eine Sammel-URL haben.
— Park

Wie könnte das mit Regexs funktionieren? Wenn die ursprüngliche URL beispielsweise mit einem regulären Ausdruck mit einem Kundennamen übereinstimmt
— Nicolò Gasparini

2

Ich hatte auch das gleiche Problem. Meine Lösung wurde mit einem (| /) vor die Endzeile meines regulären Ausdrucks gesetzt.

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


1

Fügen Sie einen Schrägstrich ohne Weiterleitung hinzu und verwenden Sie ihn anstelle von CommonMiddleware in den Einstellungen, Django 2.1:

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

Fügen Sie Ihrem Haupt-App-Verzeichnis middleware.py hinzu :

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

Ich hatte das gleiche Problem. In meinem Fall war es ein veralteter Rest einer alten Version in urls.py vor statischen Dateien:

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

MEDIA_URL war leer, daher stimmte dieses Muster mit allem überein.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.