94
votes

I've got two applications located on two separate computers. On computer A, in the urls.py file I have a line like the following:

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

And that url will work for both mySite.com/cast/ and mySite.com/cast. But on computer B I have a similar url written out like:

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

For some reason on computer B the url mySite.com/login/ will work but mySite.com/login will hang and won't direct back to mySite.com/login/ like it will on computer A. Is there something I missed? Both url.py files look identical to me.

6

6 Answers

109
votes

check your APPEND_SLASH setting in the settings.py file

more info in the django docs

204
votes

Or you can write your urls like this:

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

The question sign after the trailing slash makes it optional in regexp. Use it if for some reasons you don't want to use APPEND_SLASH setting.

21
votes

This improves on @Michael Gendin's answer. His answer serves the identical page with two separate URLs. It would be better to have login automatically redirect to login/, and then serve the latter as the main page:

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

I've had the same problem too. My solution was put an (|/) before the end line of my regular expression.

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

1
votes

Append slash without redirect, use it instead of CommonMiddleware in settings, Django 2.1:

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

Add to your main app directory 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
votes

I've had the same problem. In my case it was a stale leftover from some old version in urls.py, from before staticfiles:

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

MEDIA_URL was empty, so this pattern matched everything.