url django tanpa garis miring tidak mengalihkan

89

Saya punya dua aplikasi yang terletak di dua komputer terpisah. Di komputer A, di urls.pyfile saya memiliki baris seperti berikut:

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

Dan url itu akan berfungsi untuk mySite.com/cast/dan mySite.com/cast. Tetapi di komputer BI memiliki url serupa yang ditulis seperti:

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

Untuk beberapa alasan di komputer B url mySite.com/login/ akan berfungsi tetapi mySite.com/loginakan hang dan tidak langsung kembali mySite.com/login/seperti pada komputer A. Apakah ada sesuatu yang saya lewatkan? Kedua url.pyfile terlihat identik dengan saya.

apa apa
sumber

Jawaban:

103

periksa APPEND_SLASHpengaturan Anda di file settings.py

info lebih lanjut di dokumen django

Jiaaro
sumber
4
"Jika disetel ke True, jika URL permintaan tidak cocok dengan pola apa pun di URLconf dan tidak diakhiri dengan garis miring, pengalihan HTTP dikeluarkan ke URL yang sama dengan menambahkan garis miring. Perhatikan bahwa pengalihan dapat menyebabkan semua data yang dikirimkan dalam permintaan POST akan hilang. ". "Pengaturan APPEND_SLASH hanya digunakan jika CommonMiddleware diinstal ...". Saya lebih suka jawaban Michael Gendin untuk solusi yang lebih bersih.
Wtower
3
Ini tidak bekerja jika Anda menggunakan url "tangkap semua" tambahan di entri terakhir pola url Anda. Jawaban @ speedplane akan berfungsi bahkan dalam situasi tersebut. Tapi, tentu saja, ini lebih sederhana dan harus digunakan jika tidak ada entri urlpattern "tangkap semua".
np8
195

Atau Anda dapat menulis url Anda seperti ini:

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

Tanda tanya setelah garis miring membuatnya opsional di regexp. Gunakan jika karena alasan tertentu Anda tidak ingin menggunakan setelan APPEND_SLASH.

Michael Gendin
sumber
12
Sebut saya naif - tetapi mengapa jawaban ini tidak mendapat satu juta suara positif dan entri di faq django?
Fergal Moran
42
Cukup yakin Anda tidak ingin melakukan ini karena alasan SEO - lebih baik mengarahkan ke URL kanonis daripada memiliki dua URL yang valid.
Brian Frantz
47
Jika Anda membuat RESTful API menggunakan Django, ini bisa menjadi solusi yang baik ketika pengembang POST data langsung ke URL titik akhir. Saat menggunakan APPEND_SLASH, jika mereka secara tidak sengaja mengirimnya tanpa garis miring, dan urlconf Anda DENGAN garis miring, mereka akan mendapatkan pengecualian tentang kehilangan data saat mengarahkan permintaan POST.
OrPo
5
Masalah dengan solusi ini adalah Anda menyajikan halaman yang sama di bawah 2 url (dengan dan tanpa trailing /) - ceroboh, buruk untuk crawler, lebih sulit untuk dipertahankan, lebih sulit untuk bermigrasi ke sistem baru (karena sangat mudah untuk diabaikan)
Jiaaro
Jawaban yang bagus. Saya lebih suka untuk tidak mengizinkan garis miring (karena ini menandakan awal dari sesuatu yang baru, bukan akhir dari sesuatu (mis. / Etc), tetapi ini memungkinkan untuk standar (/ view) dan non-standar (/ view /).
David Betz
19

Ini meningkatkan jawaban @Michael Gendin. Jawabannya menyajikan halaman yang identik dengan dua URL terpisah. Akan lebih baik jika loginmengalihkan secara otomatis ke login/, dan kemudian menyajikan yang terakhir sebagai halaman utama:

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"),
)
speedplane
sumber
Sangat berguna ketika Anda memiliki URL penampung-semua di bagian akhir.
thclark
Bagaimana ini bisa bekerja dengan regex? Jika url asli cocok dengan regex dengan nama klien misalnya
Nicolò Gasparini
@ NicolòGasparini - versi terbaru dari Django mempunyai pattern_namearg yang digunakan redirectbersama dengan semua url arg yang cocok.
Tim Tisdall
2

Saya juga mengalami masalah yang sama. Solusi saya meletakkan (| /) sebelum garis akhir ekspresi reguler saya.

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

Atahualpa Silva Falcón
sumber
1

Tambahkan garis miring tanpa pengalihan , gunakan itu sebagai ganti CommonMiddleware dalam pengaturan, Django 2.1:

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

Tambahkan ke direktori aplikasi utama Anda 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
Max Tkachenko
sumber
0

Saya punya masalah yang sama. Dalam kasus saya, itu adalah sisa basi dari beberapa versi lama di urls.py, dari sebelum staticfiles:

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

MEDIA_URL kosong, jadi pola ini cocok dengan semuanya.

janek37
sumber