các url django không có dấu gạch chéo ở cuối không chuyển hướng


89

Tôi có hai ứng dụng nằm trên hai máy tính riêng biệt. Trên máy tính A, trong urls.pytệp tôi có một dòng như sau:

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

Và url đó sẽ hoạt động cho cả mySite.com/cast/mySite.com/cast. Nhưng trên máy tính BI có một url tương tự được viết như:

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

Vì một số lý do trên máy tính B, url mySite.com/login/ sẽ hoạt động nhưng mySite.com/loginsẽ bị treo và không quay lại mySite.com/login/như trên máy tính A. Có điều gì tôi đã bỏ sót không? Cả hai url.pytập tin trông giống hệt tôi.

Câu trả lời:


103

kiểm tra APPEND_SLASHcài đặt của bạn trong tệp settings.py

thêm thông tin trong tài liệu django


4
"Khi được đặt thành True, nếu URL yêu cầu không khớp với bất kỳ mẫu nào trong URLconf và nó không kết thúc bằng dấu gạch chéo, chuyển hướng HTTP sẽ được cấp cho cùng một URL có thêm dấu gạch chéo. Lưu ý rằng chuyển hướng có thể gây ra bất kỳ dữ liệu nào được gửi trong một yêu cầu POST sẽ bị mất. ". "Cài đặt APPEND_SLASH chỉ được sử dụng nếu CommonMiddleware được cài đặt ...". Tôi thích câu trả lời của Michael Gendin cho một giải pháp sạch hơn.
Wtower

3
Điều này không hoạt động nếu bạn đang sử dụng url "bắt tất cả" bổ sung ở mục nhập cuối cùng của urlpatterns của bạn. Câu trả lời của @ speedplane sẽ hoạt động ngay cả trong những tình huống đó. Nhưng, tất nhiên, điều này đơn giản hơn và nên được sử dụng nếu không có mục nhập urlpattern "bắt tất cả".
np8

195

Hoặc bạn có thể viết các url của mình như sau:

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

Dấu hỏi sau dấu gạch chéo làm cho nó trở thành tùy chọn trong regexp. Sử dụng nó nếu vì một số lý do bạn không muốn sử dụng cài đặt APPEND_SLASH.


12
Gọi tôi là ngây thơ - nhưng tại sao câu trả lời này không có một triệu ủng hộ và một mục trong câu hỏi thường gặp về django?
Fergal Moran,

42
Khá chắc chắn rằng bạn không muốn làm điều này vì lý do SEO - tốt hơn nên chuyển hướng đến một URL chuẩn hơn là có hai URL hợp lệ.
Brian Frantz

47
Nếu bạn đang tạo một API RESTful bằng Django, thì đây có thể là một giải pháp tốt khi các nhà phát triển ĐĂNG dữ liệu trực tiếp đến URL điểm cuối. Khi sử dụng APPEND_SLASH, nếu họ vô tình gửi nó mà không có dấu gạch chéo và urlconf của bạn CÓ dấu gạch chéo, họ sẽ nhận được một ngoại lệ về việc mất dữ liệu khi chuyển hướng yêu cầu POST.
OrPo

5
Vấn đề với giải pháp này là bạn đang cung cấp cùng một trang dưới 2 url (có và không có dấu /) - cẩu thả, không tốt cho trình thu thập thông tin, khó bảo trì hơn, khó chuyển sang hệ thống mới (vì nó rất dễ bị bỏ qua)
Jiaaro

Câu trả lời tốt. Tôi muốn không cho phép dấu gạch chéo (vì nó biểu thị sự bắt đầu của điều gì đó mới, không phải kết thúc của điều gì đó (ví dụ / v.v.), nhưng điều này cho phép tiêu chuẩn (/ view) và không chuẩn (/ view /).
David Betz

19

Điều này cải thiện câu trả lời của @Michael Gendin. Câu trả lời của anh ấy phục vụ cùng một trang với hai URL riêng biệt. Sẽ tốt hơn nếu bạn logintự động chuyển hướng đến login/, rồi phân phát trang sau làm trang chính:

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

Rất hữu ích khi bạn có URL tóm tắt ở cuối.
thclark

Làm thế nào điều này có thể hoạt động với regexs? Ví dụ: nếu url gốc khớp với regex với tên khách hàng
Nicolò Gasparini,

@ NicolòGasparini - các phiên bản mới hơn của Django có một lập pattern_nameluận được sử dụng redirectcùng với tất cả các args url phù hợp.
Tim Tisdall

2

Tôi cũng gặp vấn đề tương tự. Giải pháp của tôi đã được đặt một (| /) trước dòng cuối của biểu thức chính quy của tôi.

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


1

Nối dấu gạch chéo mà không chuyển hướng , sử dụng nó thay vì CommonMiddleware trong cài đặt, Django 2.1:

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

Thêm vào thư mục ứng dụng chính của bạn 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

Tôi đã có cùng một vấn đề. Trong trường hợp của tôi, đó là bản cũ còn sót lại từ một số phiên bản cũ trong urls.py, từ trước staticfiles:

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

MEDIA_URL trống, vì vậy mẫu này phù hợp với mọi thứ.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.