django urls ที่ไม่มีเครื่องหมายทับจะไม่เปลี่ยนเส้นทาง


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ไฟล์ดูเหมือนกับฉัน

คำตอบ:


104

ตรวจสอบAPPEND_SLASHการตั้งค่าของคุณในไฟล์ settings.py

ข้อมูลเพิ่มเติมใน django docs


4
"เมื่อตั้งค่าเป็น True หาก URL คำขอไม่ตรงกับรูปแบบใด ๆ ใน URLconf และไม่ได้ลงท้ายด้วยเครื่องหมายทับการเปลี่ยนเส้นทาง HTTP จะออกไปยัง URL เดียวกันโดยมีเครื่องหมายทับต่อท้ายโปรดทราบว่าการเปลี่ยนเส้นทางอาจทำให้ ข้อมูลใด ๆ ที่ส่งมาในคำขอ POST จะสูญหาย ". "การตั้งค่า APPEND_SLASH จะใช้เฉพาะเมื่อติดตั้ง CommonMiddleware ... " ฉันชอบคำตอบของ Michael Gendin สำหรับโซลูชันที่สะอาดกว่า
Wtower

3
วิธีนี้ใช้ไม่ได้หากคุณใช้ URL "catch all" เพิ่มเติมที่รายการสุดท้ายของรูปแบบ URL ของคุณ คำตอบของ @ speedplane จะใช้ได้แม้ในสถานการณ์เหล่านั้น แต่แน่นอนว่าวิธีนี้ง่ายกว่าและควรใช้หากไม่มีรายการ URL รูปแบบ "จับทั้งหมด"
np8

196

หรือคุณสามารถเขียน URL ของคุณดังนี้:

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

เครื่องหมายคำถามหลังเครื่องหมายทับทำให้เป็นทางเลือกใน regexp ใช้หากเหตุผลบางประการที่คุณไม่ต้องการใช้การตั้งค่า APPEND_SLASH


12
เรียกฉันว่าไร้เดียงสา - แต่ทำไมคำตอบนี้ถึงไม่ได้รับการโหวตมากกว่าหนึ่งล้านครั้งและรายการในคำถามที่พบบ่อยของ django?
Fergal Moran

42
ค่อนข้างแน่ใจว่าคุณไม่ต้องการทำเช่นนี้ด้วยเหตุผลด้าน SEO - ควรเปลี่ยนเส้นทางไปยัง URL ตามรูปแบบบัญญัติดีกว่าการมี URL ที่ถูกต้องสองรายการ
Brian Frantz

47
หากคุณกำลังสร้าง RESTful API โดยใช้ Django นี่อาจเป็นทางออกที่ดีเมื่อนักพัฒนาโพสต์ข้อมูลไปยัง URL ปลายทางโดยตรง เมื่อใช้APPEND_SLASHหากพวกเขาส่งโดยไม่ได้ตั้งใจโดยไม่มีเครื่องหมายทับและ urlconf ของคุณอยู่ด้วยเครื่องหมายทับพวกเขาจะได้รับข้อยกเว้นเกี่ยวกับข้อมูลที่สูญหายเมื่อเปลี่ยนเส้นทางคำขอ POST
OrPo

5
ปัญหาในการแก้ปัญหานี้คือคุณให้บริการหน้าเว็บเดียวกันภายใต้ 2 url (มีและไม่มีต่อท้าย/) - เลอะเทอะไม่ดีสำหรับโปรแกรมรวบรวมข้อมูลดูแลรักษายากกว่าโยกย้ายไปยังระบบใหม่ได้ยากขึ้น (เนื่องจากมองข้ามได้ง่ายมาก)
Jiaaro

1
ไม่มีหัวข้อ (Django / Python) แต่ในฐานะคนที่มีประสบการณ์ SEO มานานหลายปีฉันสามารถบอกคุณได้ว่าหากคุณต้องการเพิ่มประสิทธิภาพสำหรับเครื่องมือค้นหาคุณไม่ต้องการ URL 2 เวอร์ชันที่เหมือนกัน site.com/users เป็น url ที่แตกต่างจาก site.com/users/ นั่นไม่ใช่สิ่งที่คุณต้องการสำหรับ SEO คุณต้องการ url และเนื้อหาเพียง 1 เวอร์ชัน! เลือกเพียง 1 เวอร์ชันและตรวจสอบให้แน่ใจว่าคุณเปลี่ยนเส้นทางอื่นอย่างถูกต้อง
Dani

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

วิธีนี้ใช้กับ regexs ได้อย่างไร หาก URL เดิมตรงกับนิพจน์ทั่วไปกับชื่อไคลเอ็นต์เช่น
Nicolò Gasparini

@ NicolòGasparini - Django เวอร์ชันใหม่กว่ามีpattern_nameอาร์กิวเมนต์ที่ใช้redirectร่วมกับอาร์เรย์URL ทั้งหมดที่ตรงกัน
Tim Tisdall

2

ฉันก็มีปัญหาเหมือนกัน วิธีแก้ปัญหาของฉันใส่ (| /) ก่อนบรรทัดท้ายของนิพจน์ทั่วไปของฉัน

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


1

ต่อท้ายทับโดยไม่เปลี่ยนเส้นทางใช้แทน CommonMiddleware ในการตั้งค่า Django 2.1:

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

เพิ่มลงในมิดเดิลแวร์ไดเร็กทอรีหลักของแอปของคุณ:

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 ว่างเปล่าดังนั้นรูปแบบนี้จึงตรงกับทุกอย่าง

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.