Sonunda eğik çizgi olmayan django url'leri yönlendirme yapmaz


89

İki ayrı bilgisayarda bulunan iki uygulamam var. A bilgisayarında, urls.pydosyada aşağıdaki gibi bir satır var:

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

Ve bu url hem mySite.com/cast/ve için çalışacaktır mySite.com/cast. Ancak bilgisayar BI'da aşağıdaki gibi yazılmış benzer bir url var:

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

B bilgisayarında bazı nedenlerden dolayı url mySite.com/login/ çalışacak, ancak mySite.com/logintakılacak ve mySite.com/login/A bilgisayarındaki gibi geri dönmeyecek. Kaçırdığım bir şey var mı? Her iki url.pydosya da benimle aynı görünüyor.

Yanıtlar:


104

APPEND_SLASHsettings.py dosyasında ayarınızı kontrol edin

django belgelerinde daha fazla bilgi


4
"True olarak ayarlandığında, istek URL'si URLconf'taki modellerden hiçbiriyle eşleşmiyorsa ve eğik çizgiyle bitmiyorsa, aynı URL'ye bölü çizgisi eklenmiş bir HTTP yeniden yönlendirmesi yayınlanır. Yeniden yönlendirmenin neden olabileceğini unutmayın. POST isteğinde gönderilen verilerin kaybolması. " "APPEND_SLASH ayarı yalnızca CommonMiddleware yüklüyse kullanılır ...". Daha temiz bir çözüm için Michael Gendin'in cevabını tercih ediyorum.
Wtower

3
Url şablonlarınızın son girişinde ek "tümünü yakala" url kullanıyorsanız bu işe yaramaz. @ speedplane'in cevabı bu durumlarda bile işe yarayacaktır. Ancak, elbette, bu daha basittir ve "tüm url şablonu" girişleri yoksa kullanılmalıdır.
np8

196

Ya da URL'lerinizi şöyle yazabilirsiniz:

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

Sondaki eğik çizgiden sonraki soru işareti, normal ifadede onu isteğe bağlı hale getirir. Bazı nedenlerden dolayı APPEND_SLASH ayarını kullanmak istemiyorsanız kullanın.


12
Bana saf deyin - ama neden bu yanıt bir milyon olumlu oy ve django SSS'ye bir giriş almadı?
Fergal Moran

42
Bunu SEO nedenleriyle yapmak istemediğinize eminim - iki geçerli URL'ye sahip olmaktansa kanonik bir URL'ye yeniden yönlendirmek daha iyidir.
Brian Frantz

47
Django kullanarak bir RESTful API oluşturuyorsanız, geliştiricilerin POST verilerini doğrudan uç nokta URL'sine gönderirken bu iyi bir çözüm olabilir. Kullanırken APPEND_SLASH, yanlışlıkla bölü çizgisi olmadan gönderirlerse ve urlconf'unuz sondaki eğik çizgiyle birlikte ise, POST isteklerini yeniden yönlendirirken veri kaybı hakkında bir istisna alırlar.
OrPo

5
Bu çözümle ilgili sorun, aynı sayfayı 2 url altında (sonda olan ve olmayan /) sunmanızdır - özensiz, tarayıcılar için kötü, bakımı daha zor, yeni bir sisteme geçmek daha zor (çünkü gözden kaçırmak çok kolay)
Jiaaro

1
Konu dışı (Django / Python) ama yıllarca SEO deneyimi olan biri olarak, Arama motorları için optimize etmek istiyorsanız, aynı URL'nin 2 versiyonunu istemediğinizi söyleyebilirim. site.com/users, site.com/users/ adresinden farklı bir url'dir. SEO için istediğiniz bu değil. Bir url ve içeriğin sadece 1 versiyonuna ihtiyacınız var! Yalnızca 1 sürümü seçin ve diğerini doğru bir şekilde yönlendirdiğinizden emin olun.
Dani

19

Bu, @Michael Gendin'in cevabını iyileştirir. Cevabı aynı sayfayı iki ayrı URL ile sunuyor. loginOtomatik olarak adresine yeniden yönlendirmeniz login/ve ardından ikincisini ana sayfa olarak sunmanız daha iyi olur :

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

Sonunda tümünü yakalama URL'niz olduğunda çok kullanışlıdır.
thclark

Bu normal ifadelerle nasıl çalışabilir? Orijinal url, örneğin bir müşteri adıyla bir normal ifadeyle eşleşiyorsa
Nicolò Gasparini

@ NicolòGasparini - Django'nun daha yeni sürümlerinde , eşleşen tüm url argümanlarıyla birlikte pattern_namekullanılan bir argüman bulunur redirect.
Tim Tisdall

2

Ben de aynı sorunu yaşadım. Benim çözümüm, düzenli ifademin son satırının önüne (| /) koyuldu.

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


1

Yönlendirme olmadan eğik çizgi ekleyin , ayarlarda CommonMiddleware yerine kullanın, Django 2.1:

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

Ana uygulama dizininize middleware.py ekleyin :

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

Ben de aynı sorunu yaşadım. Benim durumumda, urls.py'deki bazı eski sürümlerden statik dosyalar öncesinden kalan eski bir kalıntıydı:

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

MEDIA_URL boş olduğu için bu kalıp her şeyle eşleşti.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.