简体   繁体   中英

Django URL logical OR misunderstood

I need my django application connect two different URLs to the same view. When I use regular expression, the result is different from what I expect:

from django.http import HttpResponse
from django.urls import re_path


def readme(request):
    return HttpResponse('My test', content_type='text/plain')


urlpatterns = [
    re_path(r'^(readme|help)$', readme),
]

I should render both

http://127.0.0.1:8000/readme

http://127.0.0.1:8000/help

to the same view. But I receive the following error when entering the URL in my browser:

Exception Value: readme() takes 1 positional argument but 2 were given

Exception Location: /home/ar/.local/lib/python3.8/site-packages/django/core/handlers/base.py, line 197, in _get_response


191    if response is None:
192        wrapped_callback = self.make_view_atomic(callback)
193        # If it is an asynchronous view, run it in a subthread.
194        if asyncio.iscoroutinefunction(wrapped_callback):
195            wrapped_callback = async_to_sync(wrapped_callback)
196        try:
197            response = wrapped_callback(request, *callback_args, **callback_kwargs)
198        except Exception as e:
199            response = self.process_exception_by_middleware(e, request)
200            if response is None:
201                raise
202
203    # Complain if the view returned None (a common error).

You are working with a capture group and pass this as the first item, so it will pass a string readme or help , so you can work with:

def readme(request, ):
    # item will be 'readme' or 'help'
    return HttpResponse('My test', content_type='text/plain')


urlpatterns = [
    re_path(r'^(readme|help)/$', readme),
]

It is however more elegant to define just two paths:

def readme(request):  # 🖘 no item
    return HttpResponse('My test', content_type='text/plain')


urlpatterns = [
    path(, readme),
    path(, readme),
]

and while not invalid, usually using two paths to point to the same "resource" is not considered good design. Usually you want that two different paths point to different information.

Or if you want to use it with an optional parameter:

def readme(request, lang):
    # …
    pass


inner_urls = [path('readme/', readme), path('help/', readme)]

urlpatterns = [
    path('/', include(inner_urls), kwargs={'lang': None}),
    re_path(r'^(?P<lang>en)/$', include(inner_urls)),
]

This will pass en to lang , or None if it was not "picked".

If you however want to pick a language, you likely want to use i18n_patterns(…) [Django-doc] , which is Django's internationalization solution for multi-language sites.

As error message says, the view need 2 arguments, but you have declared one. That another argument will be your readme or help .

So for solving it, you can use *args :

def readme(request, *args, **kwargs):
    return HttpResponse('My test', content_type='text/plain')

Or if you want the readme or help in your view, you can have it as just argument:

def readme(request, selected_url):
    return HttpResponse('My test', content_type='text/plain')

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM