Kaydet (Commit) a9fd740d authored tarafından Tim Graham's avatar Tim Graham

Fixed #23276 -- Deprecated passing views as strings to url().

üst 2003cb23
...@@ -67,6 +67,12 @@ def url(regex, view, kwargs=None, name=None, prefix=''): ...@@ -67,6 +67,12 @@ def url(regex, view, kwargs=None, name=None, prefix=''):
return RegexURLResolver(regex, urlconf_module, kwargs, app_name=app_name, namespace=namespace) return RegexURLResolver(regex, urlconf_module, kwargs, app_name=app_name, namespace=namespace)
else: else:
if isinstance(view, six.string_types): if isinstance(view, six.string_types):
warnings.warn(
'Support for string view arguments to url() is deprecated and '
'will be removed in Django 2.0 (got %s). Pass the callable '
'instead.' % view,
RemovedInDjango20Warning, stacklevel=2
)
if not view: if not view:
raise ImproperlyConfigured('Empty URL pattern view name not permitted (for pattern %r)' % regex) raise ImproperlyConfigured('Empty URL pattern view name not permitted (for pattern %r)' % regex)
if prefix: if prefix:
......
...@@ -5,6 +5,7 @@ from django.conf.urls import patterns, url ...@@ -5,6 +5,7 @@ from django.conf.urls import patterns, url
from django.core.urlresolvers import LocaleRegexURLResolver from django.core.urlresolvers import LocaleRegexURLResolver
from django.utils import six from django.utils import six
from django.utils.deprecation import RemovedInDjango20Warning from django.utils.deprecation import RemovedInDjango20Warning
from django.views.i18n import set_language
def i18n_patterns(prefix, *args): def i18n_patterns(prefix, *args):
...@@ -30,5 +31,5 @@ def i18n_patterns(prefix, *args): ...@@ -30,5 +31,5 @@ def i18n_patterns(prefix, *args):
urlpatterns = [ urlpatterns = [
url(r'^setlang/$', 'django.views.i18n.set_language', name='set_language'), url(r'^setlang/$', set_language, name='set_language'),
] ]
...@@ -3,9 +3,10 @@ import re ...@@ -3,9 +3,10 @@ import re
from django.conf import settings from django.conf import settings
from django.conf.urls import url from django.conf.urls import url
from django.core.exceptions import ImproperlyConfigured from django.core.exceptions import ImproperlyConfigured
from django.views.static import serve
def static(prefix, view='django.views.static.serve', **kwargs): def static(prefix, view=serve, **kwargs):
""" """
Helper function to return a URL pattern for serving files in debug mode. Helper function to return a URL pattern for serving files in debug mode.
......
...@@ -3,7 +3,7 @@ from django.contrib import admin ...@@ -3,7 +3,7 @@ from django.contrib import admin
from django.contrib.auth import context_processors from django.contrib.auth import context_processors
from django.contrib.auth.forms import AuthenticationForm from django.contrib.auth.forms import AuthenticationForm
from django.contrib.auth.urls import urlpatterns from django.contrib.auth.urls import urlpatterns
from django.contrib.auth.views import password_reset, login from django.contrib.auth import views
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
from django.contrib.messages.api import info from django.contrib.messages.api import info
from django.http import HttpResponse, HttpRequest from django.http import HttpResponse, HttpRequest
...@@ -67,29 +67,29 @@ def userpage(request): ...@@ -67,29 +67,29 @@ def userpage(request):
def custom_request_auth_login(request): def custom_request_auth_login(request):
return login(request, authentication_form=CustomRequestAuthenticationForm) return views.login(request, authentication_form=CustomRequestAuthenticationForm)
# special urls for auth test cases # special urls for auth test cases
urlpatterns += [ urlpatterns += [
url(r'^logout/custom_query/$', 'django.contrib.auth.views.logout', dict(redirect_field_name='follow')), url(r'^logout/custom_query/$', views.logout, dict(redirect_field_name='follow')),
url(r'^logout/next_page/$', 'django.contrib.auth.views.logout', dict(next_page='/somewhere/')), url(r'^logout/next_page/$', views.logout, dict(next_page='/somewhere/')),
url(r'^logout/next_page/named/$', 'django.contrib.auth.views.logout', dict(next_page='password_reset')), url(r'^logout/next_page/named/$', views.logout, dict(next_page='password_reset')),
url(r'^remote_user/$', remote_user_auth_view), url(r'^remote_user/$', remote_user_auth_view),
url(r'^password_reset_from_email/$', 'django.contrib.auth.views.password_reset', dict(from_email='staffmember@example.com')), url(r'^password_reset_from_email/$', views.password_reset, dict(from_email='staffmember@example.com')),
url(r'^password_reset/custom_redirect/$', 'django.contrib.auth.views.password_reset', dict(post_reset_redirect='/custom/')), url(r'^password_reset/custom_redirect/$', views.password_reset, dict(post_reset_redirect='/custom/')),
url(r'^password_reset/custom_redirect/named/$', 'django.contrib.auth.views.password_reset', dict(post_reset_redirect='password_reset')), url(r'^password_reset/custom_redirect/named/$', views.password_reset, dict(post_reset_redirect='password_reset')),
url(r'^password_reset/html_email_template/$', 'django.contrib.auth.views.password_reset', dict(html_email_template_name='registration/html_password_reset_email.html')), url(r'^password_reset/html_email_template/$', views.password_reset, dict(html_email_template_name='registration/html_password_reset_email.html')),
url(r'^reset/custom/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$', url(r'^reset/custom/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$',
'django.contrib.auth.views.password_reset_confirm', views.password_reset_confirm,
dict(post_reset_redirect='/custom/')), dict(post_reset_redirect='/custom/')),
url(r'^reset/custom/named/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$', url(r'^reset/custom/named/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$',
'django.contrib.auth.views.password_reset_confirm', views.password_reset_confirm,
dict(post_reset_redirect='password_reset')), dict(post_reset_redirect='password_reset')),
url(r'^password_change/custom/$', 'django.contrib.auth.views.password_change', dict(post_change_redirect='/custom/')), url(r'^password_change/custom/$', views.password_change, dict(post_change_redirect='/custom/')),
url(r'^password_change/custom/named/$', 'django.contrib.auth.views.password_change', dict(post_change_redirect='password_reset')), url(r'^password_change/custom/named/$', views.password_change, dict(post_change_redirect='password_reset')),
url(r'^admin_password_reset/$', 'django.contrib.auth.views.password_reset', dict(is_admin_site=True)), url(r'^admin_password_reset/$', views.password_reset, dict(is_admin_site=True)),
url(r'^login_required/$', login_required(password_reset)), url(r'^login_required/$', login_required(views.password_reset)),
url(r'^login_required_login_url/$', login_required(password_reset, login_url='/somewhere/')), url(r'^login_required_login_url/$', login_required(views.password_reset, login_url='/somewhere/')),
url(r'^auth_processor_no_attr_access/$', auth_processor_no_attr_access), url(r'^auth_processor_no_attr_access/$', auth_processor_no_attr_access),
url(r'^auth_processor_attr_access/$', auth_processor_attr_access), url(r'^auth_processor_attr_access/$', auth_processor_attr_access),
......
from django.conf import settings from django.conf import settings
from django.conf.urls.static import static from django.conf.urls.static import static
from django.contrib.staticfiles.views import serve
urlpatterns = [] urlpatterns = []
...@@ -10,7 +11,7 @@ def staticfiles_urlpatterns(prefix=None): ...@@ -10,7 +11,7 @@ def staticfiles_urlpatterns(prefix=None):
""" """
if prefix is None: if prefix is None:
prefix = settings.STATIC_URL prefix = settings.STATIC_URL
return static(prefix, view='django.contrib.staticfiles.views.serve') return static(prefix, view=serve)
# Only append if urlpatterns are empty # Only append if urlpatterns are empty
if settings.DEBUG and not urlpatterns: if settings.DEBUG and not urlpatterns:
......
...@@ -21,7 +21,9 @@ def serve(request, path, insecure=False, **kwargs): ...@@ -21,7 +21,9 @@ def serve(request, path, insecure=False, **kwargs):
To use, put a URL pattern such as:: To use, put a URL pattern such as::
(r'^(?P<path>.*)$', 'django.contrib.staticfiles.views.serve') from django.contrib.staticfiles import views
url(r'^(?P<path>.*)$', views.serve)
in your URLconf. in your URLconf.
......
...@@ -24,7 +24,9 @@ def serve(request, path, document_root=None, show_indexes=False): ...@@ -24,7 +24,9 @@ def serve(request, path, document_root=None, show_indexes=False):
To use, put a URL pattern such as:: To use, put a URL pattern such as::
(r'^(?P<path>.*)$', 'django.views.static.serve', {'document_root': '/path/to/my/files/'}) from django.views.static import serve
url(r'^(?P<path>.*)$', serve, {'document_root': '/path/to/my/files/'})
in your URLconf. You must provide the ``document_root`` param. You may in your URLconf. You must provide the ``document_root`` param. You may
also set ``show_indexes`` to ``True`` if you'd like to serve a basic index also set ``show_indexes`` to ``True`` if you'd like to serve a basic index
......
...@@ -44,6 +44,8 @@ about each item can often be found in the release notes of two versions prior. ...@@ -44,6 +44,8 @@ about each item can often be found in the release notes of two versions prior.
* The ``unordered_list`` filter will no longer support old style lists. * The ``unordered_list`` filter will no longer support old style lists.
* Support for string ``view`` arguments to ``url()`` will be removed.
.. _deprecation-removed-in-1.9: .. _deprecation-removed-in-1.9:
1.9 1.9
......
...@@ -186,10 +186,12 @@ example above:: ...@@ -186,10 +186,12 @@ example above::
from django.conf.urls import url from django.conf.urls import url
from . import views
urlpatterns = [ urlpatterns = [
url(r'^articles/([0-9]{4})/$', 'news.views.year_archive'), url(r'^articles/([0-9]{4})/$', views.year_archive),
url(r'^articles/([0-9]{4})/([0-9]{2})/$', 'news.views.month_archive'), url(r'^articles/([0-9]{4})/([0-9]{2})/$', views.month_archive),
url(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', 'news.views.article_detail'), url(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', views.article_detail),
] ]
The code above maps URLs, as simple `regular expressions`_, to the location of The code above maps URLs, as simple `regular expressions`_, to the location of
......
...@@ -2571,10 +2571,12 @@ your URLconf. Specifically, add these four patterns: ...@@ -2571,10 +2571,12 @@ your URLconf. Specifically, add these four patterns:
.. code-block:: python .. code-block:: python
url(r'^admin/password_reset/$', 'django.contrib.auth.views.password_reset', name='admin_password_reset'), from django.contrib.auth import views as auth_views
url(r'^admin/password_reset/done/$', 'django.contrib.auth.views.password_reset_done', name='password_reset_done'),
url(r'^reset/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>.+)/$', 'django.contrib.auth.views.password_reset_confirm', name='password_reset_confirm'), url(r'^admin/password_reset/$', auth_views.password_reset, name='admin_password_reset'),
url(r'^reset/done/$', 'django.contrib.auth.views.password_reset_complete', name='password_reset_complete'), url(r'^admin/password_reset/done/$', auth_views.password_reset_done, name='password_reset_done'),
url(r'^reset/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>.+)/$', auth_views.password_reset_confirm, name='password_reset_confirm'),
url(r'^reset/done/$', auth_views.password_reset_complete, name='password_reset_complete'),
(This assumes you've added the admin at ``admin/`` and requires that you put (This assumes you've added the admin at ``admin/`` and requires that you put
the URLs starting with ``^admin/`` before the line that includes the admin app the URLs starting with ``^admin/`` before the line that includes the admin app
......
...@@ -54,8 +54,10 @@ Initialization ...@@ -54,8 +54,10 @@ Initialization
To activate sitemap generation on your Django site, add this line to your To activate sitemap generation on your Django site, add this line to your
:doc:`URLconf </topics/http/urls>`:: :doc:`URLconf </topics/http/urls>`::
url(r'^sitemap\.xml$', 'django.contrib.sitemaps.views.sitemap', from django.contrib.sitemaps.views import sitemap
{'sitemaps': sitemaps}, name='django.contrib.sitemaps.views.sitemap')
url(r'^sitemap\.xml$', sitemap, {'sitemaps': sitemaps},
name='django.contrib.sitemaps.views.sitemap')
This tells Django to build a sitemap when a client accesses :file:`/sitemap.xml`. This tells Django to build a sitemap when a client accesses :file:`/sitemap.xml`.
...@@ -277,6 +279,7 @@ Here's an example of a :doc:`URLconf </topics/http/urls>` using both:: ...@@ -277,6 +279,7 @@ Here's an example of a :doc:`URLconf </topics/http/urls>` using both::
from django.conf.urls import url from django.conf.urls import url
from django.contrib.sitemaps import FlatPageSitemap, GenericSitemap from django.contrib.sitemaps import FlatPageSitemap, GenericSitemap
from django.contrib.sitemaps.views import sitemap
from blog.models import Entry from blog.models import Entry
info_dict = { info_dict = {
...@@ -294,8 +297,8 @@ Here's an example of a :doc:`URLconf </topics/http/urls>` using both:: ...@@ -294,8 +297,8 @@ Here's an example of a :doc:`URLconf </topics/http/urls>` using both::
# ... # ...
# the sitemap # the sitemap
url(r'^sitemap\.xml$', 'django.contrib.sitemaps.views.sitemap', url(r'^sitemap\.xml$', sitemap, {'sitemaps': sitemaps},
{'sitemaps': sitemaps}, name='django.contrib.sitemaps.views.sitemap'), name='django.contrib.sitemaps.views.sitemap'),
] ]
.. _URLconf: ../url_dispatch/ .. _URLconf: ../url_dispatch/
...@@ -311,8 +314,11 @@ the sitemap. For example:: ...@@ -311,8 +314,11 @@ the sitemap. For example::
# sitemaps.py # sitemaps.py
from django.contrib import sitemaps from django.contrib import sitemaps
from django.contrib.sitemaps.views import sitemap
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from . import views
class StaticViewSitemap(sitemaps.Sitemap): class StaticViewSitemap(sitemaps.Sitemap):
priority = 0.5 priority = 0.5
changefreq = 'daily' changefreq = 'daily'
...@@ -332,12 +338,12 @@ the sitemap. For example:: ...@@ -332,12 +338,12 @@ the sitemap. For example::
} }
urlpatterns = [ urlpatterns = [
url(r'^$', 'views.main', name='main'), url(r'^$', views.main, name='main'),
url(r'^about/$', 'views.about', name='about'), url(r'^about/$', views.about, name='about'),
url(r'^license/$', 'views.license', name='license'), url(r'^license/$', views.license, name='license'),
# ... # ...
url(r'^sitemap\.xml$', 'django.contrib.sitemaps.views.sitemap', url(r'^sitemap\.xml$', sitemap, {'sitemaps': sitemaps},
{'sitemaps': sitemaps}, name='django.contrib.sitemaps.views.sitemap') name='django.contrib.sitemaps.views.sitemap')
] ]
......
...@@ -78,7 +78,7 @@ The ``optional_dictionary`` and ``optional_name`` parameters are described in ...@@ -78,7 +78,7 @@ The ``optional_dictionary`` and ``optional_name`` parameters are described in
static() static()
-------- --------
.. function:: static.static(prefix, view='django.views.static.serve', **kwargs) .. function:: static.static(prefix, view=django.views.static.serve, **kwargs)
Helper function to return a URL pattern for serving files in debug mode:: Helper function to return a URL pattern for serving files in debug mode::
...@@ -89,6 +89,11 @@ Helper function to return a URL pattern for serving files in debug mode:: ...@@ -89,6 +89,11 @@ Helper function to return a URL pattern for serving files in debug mode::
# ... the rest of your URLconf goes here ... # ... the rest of your URLconf goes here ...
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
.. versionchanged:: 1.8
The ``view`` argument changed from a string
(``'django.views.static.serve'``) to the function.
url() url()
----- -----
...@@ -111,9 +116,14 @@ function or method. See :ref:`views-extra-options` for an example. ...@@ -111,9 +116,14 @@ function or method. See :ref:`views-extra-options` for an example.
See :ref:`Naming URL patterns <naming-url-patterns>` for why the ``name`` See :ref:`Naming URL patterns <naming-url-patterns>` for why the ``name``
parameter is useful. parameter is useful.
The ``prefix`` parameter has the same meaning as the first argument to .. deprecated:: 1.8
``patterns()`` and is only relevant when you're passing a string as the
``view`` parameter. Support for string ``view`` arguments is deprecated and will be removed in
Django 2.0. Pass the callable instead.
The ``prefix`` parameter has the same meaning as the first argument to
``patterns()`` and is only relevant when you're passing a string as the
``view`` parameter.
include() include()
--------- ---------
......
...@@ -548,6 +548,13 @@ Updating your code is as simple as ensuring that ``urlpatterns`` is a list of ...@@ -548,6 +548,13 @@ Updating your code is as simple as ensuring that ``urlpatterns`` is a list of
url('^other/$', views.otherview), url('^other/$', views.otherview),
] ]
Passing a string as ``view`` to :func:`~django.conf.urls.url`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Related to the previous item, referencing views as strings in the ``url()``
function is deprecated. Pass the callable view as described in the previous
section instead.
``django.test.SimpleTestCase.urls`` ``django.test.SimpleTestCase.urls``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
...@@ -580,8 +587,10 @@ for reversing instead. ...@@ -580,8 +587,10 @@ for reversing instead.
If you are using :mod:`django.contrib.sitemaps`, add the ``name`` argument to If you are using :mod:`django.contrib.sitemaps`, add the ``name`` argument to
the ``url`` that references :func:`django.contrib.sitemaps.views.sitemap`:: the ``url`` that references :func:`django.contrib.sitemaps.views.sitemap`::
url(r'^sitemap\.xml$', 'django.contrib.sitemaps.views.sitemap', from django.contrib.sitemaps.views import sitemap
{'sitemaps': sitemaps}, name='django.contrib.sitemaps.views.sitemap')
url(r'^sitemap\.xml$', sitemap, {'sitemaps': sitemaps},
name='django.contrib.sitemaps.views.sitemap')
to ensure compatibility when reversing by Python path is removed in Django 2.0. to ensure compatibility when reversing by Python path is removed in Django 2.0.
......
...@@ -74,11 +74,13 @@ Here's a sample URLconf:: ...@@ -74,11 +74,13 @@ Here's a sample URLconf::
from django.conf.urls import url from django.conf.urls import url
from . import views
urlpatterns = [ urlpatterns = [
url(r'^articles/2003/$', 'news.views.special_case_2003'), url(r'^articles/2003/$', views.special_case_2003),
url(r'^articles/([0-9]{4})/$', 'news.views.year_archive'), url(r'^articles/([0-9]{4})/$', views.year_archive),
url(r'^articles/([0-9]{4})/([0-9]{2})/$', 'news.views.month_archive'), url(r'^articles/([0-9]{4})/([0-9]{2})/$', views.month_archive),
url(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', 'news.views.article_detail'), url(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', views.article_detail),
] ]
Notes: Notes:
...@@ -96,7 +98,7 @@ Example requests: ...@@ -96,7 +98,7 @@ Example requests:
* A request to ``/articles/2005/03/`` would match the third entry in the * A request to ``/articles/2005/03/`` would match the third entry in the
list. Django would call the function list. Django would call the function
``news.views.month_archive(request, '2005', '03')``. ``views.month_archive(request, '2005', '03')``.
* ``/articles/2005/3/`` would not match any URL patterns, because the * ``/articles/2005/3/`` would not match any URL patterns, because the
third entry in the list requires two digits for the month. third entry in the list requires two digits for the month.
...@@ -110,7 +112,7 @@ Example requests: ...@@ -110,7 +112,7 @@ Example requests:
pattern requires that the URL end with a slash. pattern requires that the URL end with a slash.
* ``/articles/2003/03/03/`` would match the final pattern. Django would call * ``/articles/2003/03/03/`` would match the final pattern. Django would call
the function ``news.views.article_detail(request, '2003', '03', '03')``. the function ``views.article_detail(request, '2003', '03', '03')``.
.. _Dive Into Python's explanation: http://www.diveintopython.net/regular_expressions/street_addresses.html#re.matching.2.3 .. _Dive Into Python's explanation: http://www.diveintopython.net/regular_expressions/street_addresses.html#re.matching.2.3
...@@ -131,11 +133,13 @@ Here's the above example URLconf, rewritten to use named groups:: ...@@ -131,11 +133,13 @@ Here's the above example URLconf, rewritten to use named groups::
from django.conf.urls import url from django.conf.urls import url
from . import views
urlpatterns = [ urlpatterns = [
url(r'^articles/2003/$', 'news.views.special_case_2003'), url(r'^articles/2003/$', views.special_case_2003),
url(r'^articles/(?P<year>[0-9]{4})/$', 'news.views.year_archive'), url(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive),
url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', 'news.views.month_archive'), url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.month_archive),
url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<day>[0-9]{2})/$', 'news.views.article_detail'), url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<day>[0-9]{2})/$', views.article_detail),
] ]
This accomplishes exactly the same thing as the previous example, with one This accomplishes exactly the same thing as the previous example, with one
...@@ -143,11 +147,11 @@ subtle difference: The captured values are passed to view functions as keyword ...@@ -143,11 +147,11 @@ subtle difference: The captured values are passed to view functions as keyword
arguments rather than positional arguments. For example: arguments rather than positional arguments. For example:
* A request to ``/articles/2005/03/`` would call the function * A request to ``/articles/2005/03/`` would call the function
``news.views.month_archive(request, year='2005', month='03')``, instead ``views.month_archive(request, year='2005', month='03')``, instead
of ``news.views.month_archive(request, '2005', '03')``. of ``views.month_archive(request, '2005', '03')``.
* A request to ``/articles/2003/03/03/`` would call the function * A request to ``/articles/2003/03/03/`` would call the function
``news.views.article_detail(request, year='2003', month='03', day='03')``. ``views.article_detail(request, year='2003', month='03', day='03')``.
In practice, this means your URLconfs are slightly more explicit and less prone In practice, this means your URLconfs are slightly more explicit and less prone
to argument-order bugs -- and you can reorder the arguments in your views' to argument-order bugs -- and you can reorder the arguments in your views'
...@@ -191,9 +195,9 @@ Each captured argument is sent to the view as a plain Python string, regardless ...@@ -191,9 +195,9 @@ Each captured argument is sent to the view as a plain Python string, regardless
of what sort of match the regular expression makes. For example, in this of what sort of match the regular expression makes. For example, in this
URLconf line:: URLconf line::
url(r'^articles/(?P<year>[0-9]{4})/$', 'news.views.year_archive'), url(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive),
...the ``year`` argument to ``news.views.year_archive()`` will be a string, not ...the ``year`` argument to ``views.year_archive()`` will be a string, not
an integer, even though the ``[0-9]{4}`` will only match integer strings. an integer, even though the ``[0-9]{4}`` will only match integer strings.
Specifying defaults for view arguments Specifying defaults for view arguments
...@@ -205,9 +209,11 @@ Here's an example URLconf and view:: ...@@ -205,9 +209,11 @@ Here's an example URLconf and view::
# URLconf # URLconf
from django.conf.urls import url from django.conf.urls import url
from . import views
urlpatterns = [ urlpatterns = [
url(r'^blog/$', 'blog.views.page'), url(r'^blog/$', views.page),
url(r'^blog/page(?P<num>[0-9]+)/$', 'blog.views.page'), url(r'^blog/page(?P<num>[0-9]+)/$', views.page),
] ]
# View (in blog/views.py) # View (in blog/views.py)
...@@ -216,7 +222,7 @@ Here's an example URLconf and view:: ...@@ -216,7 +222,7 @@ Here's an example URLconf and view::
... ...
In the above example, both URL patterns point to the same view -- In the above example, both URL patterns point to the same view --
``blog.views.page`` -- but the first pattern doesn't capture anything from the ``views.page`` -- but the first pattern doesn't capture anything from the
URL. If the first pattern matches, the ``page()`` function will use its URL. If the first pattern matches, the ``page()`` function will use its
default argument for ``num``, ``"1"``. If the second pattern matches, default argument for ``num``, ``"1"``. If the second pattern matches,
``page()`` will use whatever ``num`` value was captured by the regex. ``page()`` will use whatever ``num`` value was captured by the regex.
...@@ -290,13 +296,16 @@ Another possibility is to include additional URL patterns by using a list of ...@@ -290,13 +296,16 @@ Another possibility is to include additional URL patterns by using a list of
from django.conf.urls import include, url from django.conf.urls import include, url
from apps.main import views as main_views
from credit import views as credit_views
extra_patterns = [ extra_patterns = [
url(r'^reports/(?P<id>[0-9]+)/$', 'credit.views.report'), url(r'^reports/(?P<id>[0-9]+)/$', credit_views.report),
url(r'^charge/$', 'credit.views.charge'), url(r'^charge/$', credit_views.charge),
] ]
urlpatterns = [ urlpatterns = [
url(r'^$', 'apps.main.views.homepage'), url(r'^$', main_views.homepage),
url(r'^help/', include('apps.help.urls')), url(r'^help/', include('apps.help.urls')),
url(r'^credit/', include(extra_patterns)), url(r'^credit/', include(extra_patterns)),
] ]
...@@ -381,7 +390,7 @@ For example:: ...@@ -381,7 +390,7 @@ For example::
] ]
In this example, for a request to ``/blog/2005/``, Django will call In this example, for a request to ``/blog/2005/``, Django will call
``blog.views.year_archive(request, year='2005', foo='bar')``. ``views.year_archive(request, year='2005', foo='bar')``.
This technique is used in the This technique is used in the
:doc:`syndication framework </ref/contrib/syndication>` to pass metadata and :doc:`syndication framework </ref/contrib/syndication>` to pass metadata and
...@@ -444,60 +453,6 @@ URLconf, regardless of whether the line's view actually accepts those options ...@@ -444,60 +453,6 @@ URLconf, regardless of whether the line's view actually accepts those options
as valid. For this reason, this technique is only useful if you're certain that as valid. For this reason, this technique is only useful if you're certain that
every view in the included URLconf accepts the extra options you're passing. every view in the included URLconf accepts the extra options you're passing.
Passing callable objects instead of strings
===========================================
Some developers find it more natural to pass the actual Python function object
rather than a string containing the path to its module. This alternative is
supported -- you can pass any callable object as the view.
For example, given this URLconf in "string" notation::
from django.conf.urls import url
urlpatterns = [
url(r'^archive/$', 'mysite.views.archive'),
url(r'^about/$', 'mysite.views.about'),
url(r'^contact/$', 'mysite.views.contact'),
]
You can accomplish the same thing by passing objects rather than strings. Just
be sure to import the objects::
from django.conf.urls import url
from mysite.views import archive, about, contact
urlpatterns = [
url(r'^archive/$', archive),
url(r'^about/$', about),
url(r'^contact/$', contact),
]
The following example is functionally identical. It's just a bit more compact
because it imports the module that contains the views, rather than importing
each view individually::
from django.conf.urls import url
from mysite import views
urlpatterns = [
url(r'^archive/$', views.archive),
url(r'^about/$', views.about),
url(r'^contact/$', views.contact),
]
The style you use is up to you.
Note that :doc:`class based views</topics/class-based-views/index>` must be
imported::
from django.conf.urls import url
from mysite.views import ClassBasedView
urlpatterns = [
url(r'^myview/$', ClassBasedView.as_view()),
]
Reverse resolution of URLs Reverse resolution of URLs
========================== ==========================
...@@ -553,9 +508,11 @@ Consider again this URLconf entry:: ...@@ -553,9 +508,11 @@ Consider again this URLconf entry::
from django.conf.urls import url from django.conf.urls import url
from . import views
urlpatterns = [ urlpatterns = [
#... #...
url(r'^articles/([0-9]{4})/$', 'news.views.year_archive', name='news-year-archive'), url(r'^articles/([0-9]{4})/$', views.year_archive, name='news-year-archive'),
#... #...
] ]
...@@ -756,9 +713,11 @@ For example:: ...@@ -756,9 +713,11 @@ For example::
from django.conf.urls import include, url from django.conf.urls import include, url
from app.helps import views
help_patterns = [ help_patterns = [
url(r'^basic/$', 'apps.help.views.views.basic'), url(r'^basic/$', views.basic),
url(r'^advanced/$', 'apps.help.views.views.advanced'), url(r'^advanced/$', views.advanced),
] ]
url(r'^help/', include((help_patterns, 'bar', 'foo'))), url(r'^help/', include((help_patterns, 'bar', 'foo'))),
......
...@@ -1100,22 +1100,25 @@ prepend the current active language code to all url patterns defined within ...@@ -1100,22 +1100,25 @@ prepend the current active language code to all url patterns defined within
from django.conf.urls import include, url from django.conf.urls import include, url
from django.conf.urls.i18n import i18n_patterns from django.conf.urls.i18n import i18n_patterns
from about import views as about_views
from news import views as news_views
from sitemap.views imort sitemap
urlpatterns = [ urlpatterns = [
url(r'^sitemap\.xml$', 'sitemap.view', name='sitemap_xml'), url(r'^sitemap\.xml$', sitemap, name='sitemap_xml'),
] ]
news_patterns = [ news_patterns = [
url(r'^$', 'news.views.index', name='index'), url(r'^$', news_views.index, name='index'),
url(r'^category/(?P<slug>[\w-]+)/$', 'news.views.category', name='category'), url(r'^category/(?P<slug>[\w-]+)/$', news_views.category, name='category'),
url(r'^(?P<slug>[\w-]+)/$', 'news.views.details', name='detail'), url(r'^(?P<slug>[\w-]+)/$', news_views.details, name='detail'),
] ]
urlpatterns += i18n_patterns( urlpatterns += i18n_patterns(
url(r'^about/$', 'about.view', name='about'), url(r'^about/$', about_views.main, name='about'),
url(r'^news/', include(news_patterns, namespace='news')), url(r'^news/', include(news_patterns, namespace='news')),
) )
After defining these URL patterns, Django will automatically add the After defining these URL patterns, Django will automatically add the
language prefix to the URL patterns that were added by the ``i18n_patterns`` language prefix to the URL patterns that were added by the ``i18n_patterns``
function. Example:: function. Example::
...@@ -1155,22 +1158,25 @@ URL patterns can also be marked translatable using the ...@@ -1155,22 +1158,25 @@ URL patterns can also be marked translatable using the
from django.conf.urls.i18n import i18n_patterns from django.conf.urls.i18n import i18n_patterns
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from about import views as about_views
from news import views as news_views
from sitemaps.views import sitemap
urlpatterns = [ urlpatterns = [
url(r'^sitemap\.xml$', 'sitemap.view', name='sitemap_xml'), url(r'^sitemap\.xml$', sitemap, name='sitemap_xml'),
] ]
news_patterns = [ news_patterns = [
url(r'^$', 'news.views.index', name='index'), url(r'^$', news_views.index, name='index'),
url(_(r'^category/(?P<slug>[\w-]+)/$'), 'news.views.category', name='category'), url(_(r'^category/(?P<slug>[\w-]+)/$'), news_views.category, name='category'),
url(r'^(?P<slug>[\w-]+)/$', 'news.views.details', name='detail'), url(r'^(?P<slug>[\w-]+)/$', news_views.details, name='detail'),
] ]
urlpatterns += i18n_patterns( urlpatterns += i18n_patterns(
url(_(r'^about/$'), 'about.view', name='about'), url(_(r'^about/$'), about_views.main, name='about'),
url(_(r'^news/'), include(news_patterns, namespace='news')), url(_(r'^news/'), include(news_patterns, namespace='news')),
) )
After you've created the translations, the After you've created the translations, the
:func:`~django.core.urlresolvers.reverse` function will return the URL in the :func:`~django.core.urlresolvers.reverse` function will return the URL in the
active language. Example:: active language. Example::
......
import os import os
from django.conf.urls import url from django.conf.urls import url
from django.utils._os import upath from django.utils._os import upath
from django.views.static import serve
here = os.path.dirname(upath(__file__)) here = os.path.dirname(upath(__file__))
urlpatterns = [ urlpatterns = [
url(r'^custom_templates/(?P<path>.*)$', 'django.views.static.serve', { url(r'^custom_templates/(?P<path>.*)$', serve, {
'document_root': os.path.join(here, 'custom_templates')}), 'document_root': os.path.join(here, 'custom_templates')}),
] ]
from django.conf.urls import url from django.conf.urls import url
from django.contrib.auth import views as auth_views
from django.views.decorators.cache import cache_page from django.views.decorators.cache import cache_page
from django.views.generic import TemplateView from django.views.generic import TemplateView
...@@ -257,5 +258,5 @@ urlpatterns = [ ...@@ -257,5 +258,5 @@ urlpatterns = [
views.BookSigningDetail.as_view()), views.BookSigningDetail.as_view()),
# Useful for testing redirects # Useful for testing redirects
url(r'^accounts/login/$', 'django.contrib.auth.views.login') url(r'^accounts/login/$', auth_views.login)
] ]
from django.conf.urls import url from django.conf.urls import url
from . import views
urlpatterns = [ urlpatterns = [
url(r'^customurlconf/noslash$', 'middleware.views.empty_view'), url(r'^customurlconf/noslash$', views.empty_view),
url(r'^customurlconf/slash/$', 'middleware.views.empty_view'), url(r'^customurlconf/slash/$', views.empty_view),
url(r'^customurlconf/needsquoting#/$', 'middleware.views.empty_view'), url(r'^customurlconf/needsquoting#/$', views.empty_view),
] ]
from django.conf.urls import url from django.conf.urls import url
from . import views
urlpatterns = [ urlpatterns = [
url(r'^noslash$', 'middleware.views.empty_view'), url(r'^noslash$', views.empty_view),
url(r'^slash/$', 'middleware.views.empty_view'), url(r'^slash/$', views.empty_view),
url(r'^needsquoting#/$', 'middleware.views.empty_view'), url(r'^needsquoting#/$', views.empty_view),
] ]
from django.conf.urls import url from django.conf.urls import url
from . import views
urlpatterns = [ urlpatterns = [
url(r'^guitarists/(\w{1,50})/$', 'model_permalink.views.empty_view', name='guitarist_detail'), url(r'^guitarists/(\w{1,50})/$', views.empty_view, name='guitarist_detail'),
] ]
...@@ -15,5 +15,5 @@ urlpatterns = [ ...@@ -15,5 +15,5 @@ urlpatterns = [
# Unicode strings are permitted everywhere. # Unicode strings are permitted everywhere.
url(r'^Юникод/(\w+)/$', views.client2, name="метка_оператора"), url(r'^Юникод/(\w+)/$', views.client2, name="метка_оператора"),
url(r'^Юникод/(?P<tag>\S+)/$', 'template_tests.views.client2', name="метка_оператора_2"), url(r'^Юникод/(?P<tag>\S+)/$', views.client2, name="метка_оператора_2"),
] ]
from django.conf.urls import url from django.conf.urls import url
from django.contrib.auth import views as auth_views
from django.views.generic import RedirectView from django.views.generic import RedirectView
from . import views from . import views
...@@ -32,6 +33,6 @@ urlpatterns = [ ...@@ -32,6 +33,6 @@ urlpatterns = [
url(r'^mass_mail_sending_view/$', views.mass_mail_sending_view), url(r'^mass_mail_sending_view/$', views.mass_mail_sending_view),
url(r'^django_project_redirect/$', views.django_project_redirect), url(r'^django_project_redirect/$', views.django_project_redirect),
url(r'^accounts/login/$', 'django.contrib.auth.views.login', {'template_name': 'login.html'}), url(r'^accounts/login/$', auth_views.login, {'template_name': 'login.html'}),
url(r'^accounts/logout/$', 'django.contrib.auth.views.logout'), url(r'^accounts/logout/$', auth_views.logout),
] ]
import warnings
from django.conf.urls import url from django.conf.urls import url
from . import views from . import views
urlpatterns = [ # Test deprecated behavior of passing strings as view to url().
# View has erroneous import # Some of these can be removed in Django 2.0 as they aren't convertable to
url(r'erroneous_inner/$', views.erroneous_view), # callabls.
# Module has erroneous import with warnings.catch_warnings(record=True):
# Remove in Django 2.0 along with erroneous_views_module as this is only warnings.filterwarnings('ignore', module='django.conf.urls')
# an issue with string in urlpatterns urlpatterns = [
url(r'erroneous_outer/$', 'urlpatterns_reverse.erroneous_views_module.erroneous_view'), # View has erroneous import
# Module is an unqualified string url(r'erroneous_inner/$', views.erroneous_view),
url(r'erroneous_unqualified/$', 'unqualified_view'), # Module has erroneous import
# View does not exist url(r'erroneous_outer/$', 'urlpatterns_reverse.erroneous_views_module.erroneous_view'),
# Remove in Django 2.0 along with erroneous_views_module as this is only # Module is an unqualified string
# an issue with string in urlpatterns url(r'erroneous_unqualified/$', 'unqualified_view'),
url(r'missing_inner/$', 'urlpatterns_reverse.views.missing_view'), # View does not exist
# View is not callable url(r'missing_inner/$', 'urlpatterns_reverse.views.missing_view'),
# Remove in Django 2.0 along with erroneous_views_module as this is only # View is not callable
# an issue with string in urlpatterns url(r'uncallable/$', 'urlpatterns_reverse.views.uncallable'),
url(r'uncallable/$', 'urlpatterns_reverse.views.uncallable'), # Module does not exist
# Module does not exist url(r'missing_outer/$', 'urlpatterns_reverse.missing_module.missing_view'),
url(r'missing_outer/$', 'urlpatterns_reverse.missing_module.missing_view'), # Regex contains an error (refs #6170)
# Regex contains an error (refs #6170) url(r'(regex_error/$', views.empty_view),
url(r'(regex_error/$', views.empty_view), ]
]
...@@ -10,9 +10,9 @@ class URLObject(object): ...@@ -10,9 +10,9 @@ class URLObject(object):
def urls(self): def urls(self):
return ([ return ([
url(r'^inner/$', 'urlpatterns_reverse.views.empty_view', name='urlobject-view'), url(r'^inner/$', views.empty_view, name='urlobject-view'),
url(r'^inner/(?P<arg1>[0-9]+)/(?P<arg2>[0-9]+)/$', 'urlpatterns_reverse.views.empty_view', name='urlobject-view'), url(r'^inner/(?P<arg1>[0-9]+)/(?P<arg2>[0-9]+)/$', views.empty_view, name='urlobject-view'),
url(r'^inner/\+\\\$\*/$', 'urlpatterns_reverse.views.empty_view', name='urlobject-special-view'), url(r'^inner/\+\\\$\*/$', views.empty_view, name='urlobject-special-view'),
], self.app_name, self.namespace) ], self.app_name, self.namespace)
urls = property(urls) urls = property(urls)
......
...@@ -2,12 +2,15 @@ import warnings ...@@ -2,12 +2,15 @@ import warnings
from django.conf.urls import patterns, url, include from django.conf.urls import patterns, url, include
from .views import empty_view, empty_view_partial, empty_view_wrapped, absolute_kwargs_view from .views import (
absolute_kwargs_view, defaults_view, empty_view, empty_view_partial,
empty_view_wrapped, nested_view,
)
other_patterns = [ other_patterns = [
url(r'non_path_include/$', empty_view, name='non_path_include'), url(r'non_path_include/$', empty_view, name='non_path_include'),
url(r'nested_path/$', 'urlpatterns_reverse.views.nested_view'), url(r'nested_path/$', nested_view),
] ]
# test deprecated patterns() function. convert to list of urls() in Django 2.0 # test deprecated patterns() function. convert to list of urls() in Django 2.0
...@@ -68,8 +71,8 @@ with warnings.catch_warnings(record=True): ...@@ -68,8 +71,8 @@ with warnings.catch_warnings(record=True):
url(r'absolute_arg_view/$', absolute_kwargs_view), url(r'absolute_arg_view/$', absolute_kwargs_view),
# Tests for #13154. Mixed syntax to test both ways of defining URLs. # Tests for #13154. Mixed syntax to test both ways of defining URLs.
url(r'defaults_view1/(?P<arg1>[0-9]+)/', 'urlpatterns_reverse.views.defaults_view', {'arg2': 1}, name='defaults'), url(r'defaults_view1/(?P<arg1>[0-9]+)/', defaults_view, {'arg2': 1}, name='defaults'),
(r'defaults_view2/(?P<arg1>[0-9]+)/', 'urlpatterns_reverse.views.defaults_view', {'arg2': 2}, 'defaults'), (r'defaults_view2/(?P<arg1>[0-9]+)/', defaults_view, {'arg2': 2}, 'defaults'),
url('^includes/', include(other_patterns)), url('^includes/', include(other_patterns)),
) )
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
from __future__ import unicode_literals from __future__ import unicode_literals
from django.conf.urls import url from django.conf.urls import url
from django.contrib.auth import views as auth_views
from django.views.generic import RedirectView from django.views.generic import RedirectView
from .models import Article, DateArticle from .models import Article, DateArticle
...@@ -27,12 +28,12 @@ numeric_days_info_dict = dict(date_based_info_dict, day_format='%d') ...@@ -27,12 +28,12 @@ numeric_days_info_dict = dict(date_based_info_dict, day_format='%d')
date_based_datefield_info_dict = dict(date_based_info_dict, queryset=DateArticle.objects.all()) date_based_datefield_info_dict = dict(date_based_info_dict, queryset=DateArticle.objects.all())
urlpatterns = [ urlpatterns = [
url(r'^accounts/login/$', 'django.contrib.auth.views.login', {'template_name': 'login.html'}), url(r'^accounts/login/$', auth_views.login, {'template_name': 'login.html'}),
url(r'^accounts/logout/$', 'django.contrib.auth.views.logout'), url(r'^accounts/logout/$', auth_views.logout),
# Special URLs for particular regression cases. # Special URLs for particular regression cases.
url('^中文/$', 'view_tests.views.redirect'), url('^中文/$', views.redirect),
url('^中文/target/$', 'view_tests.views.index_page'), url('^中文/target/$', views.index_page),
] ]
# redirects, both temporary and permanent, with non-ASCII targets # redirects, both temporary and permanent, with non-ASCII targets
......
from django.conf.urls import url from django.conf.urls import url
from . import views
urlpatterns = [ urlpatterns = [
url(r'^index/$', 'view_tests.views.index_page', name='index'), url(r'^index/$', views.index_page, name='index'),
] ]
...@@ -3,7 +3,7 @@ from os import path ...@@ -3,7 +3,7 @@ from os import path
from django.conf.urls import url, include from django.conf.urls import url, include
from django.utils._os import upath from django.utils._os import upath
from django.views import defaults, i18n from django.views import defaults, i18n, static
from . import views from . import views
...@@ -71,7 +71,7 @@ urlpatterns = [ ...@@ -71,7 +71,7 @@ urlpatterns = [
url(r'^jsi18n_template/$', views.jsi18n), url(r'^jsi18n_template/$', views.jsi18n),
# Static views # Static views
url(r'^site_media/(?P<path>.*)$', 'django.views.static.serve', {'document_root': media_dir}), url(r'^site_media/(?P<path>.*)$', static.serve, {'document_root': media_dir}),
] ]
urlpatterns += [ urlpatterns += [
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment