Fixed #21927 -- Made application and instance namespaces more distinct.
Made URL application namespaces be set in the included URLconf and instance namespaces in the call to include(). Deprecated other ways to set application and instance namespaces.
This commit is contained in:
parent
39937de7e6
commit
1e82094f1b
|
@ -13,9 +13,9 @@ Including another URLconf
|
|||
1. Add an import: from blog import urls as blog_urls
|
||||
2. Add a URL to urlpatterns: url(r'^blog/', include(blog_urls))
|
||||
"""
|
||||
from django.conf.urls import include, url
|
||||
from django.conf.urls import url
|
||||
from django.contrib import admin
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^admin/', include(admin.site.urls)),
|
||||
url(r'^admin/', admin.site.urls),
|
||||
]
|
||||
|
|
|
@ -5,7 +5,7 @@ from django.core.urlresolvers import (RegexURLPattern,
|
|||
RegexURLResolver, LocaleRegexURLResolver)
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
from django.utils import six
|
||||
from django.utils.deprecation import RemovedInDjango20Warning
|
||||
from django.utils.deprecation import RemovedInDjango20Warning, RemovedInDjango21Warning
|
||||
|
||||
|
||||
__all__ = ['handler400', 'handler403', 'handler404', 'handler500', 'include', 'patterns', 'url']
|
||||
|
@ -19,11 +19,28 @@ handler500 = 'django.views.defaults.server_error'
|
|||
def include(arg, namespace=None, app_name=None):
|
||||
if app_name and not namespace:
|
||||
raise ValueError('Must specify a namespace if specifying app_name.')
|
||||
if app_name:
|
||||
warnings.warn(
|
||||
'The app_name argument to django.conf.urls.include() is deprecated. '
|
||||
'Set the app_name in the included URLconf instead.',
|
||||
RemovedInDjango21Warning, stacklevel=2
|
||||
)
|
||||
|
||||
if isinstance(arg, tuple):
|
||||
# callable returning a namespace hint
|
||||
try:
|
||||
urlconf_module, app_name = arg
|
||||
except ValueError:
|
||||
if namespace:
|
||||
raise ImproperlyConfigured('Cannot override the namespace for a dynamic module that provides a namespace')
|
||||
raise ImproperlyConfigured(
|
||||
'Cannot override the namespace for a dynamic module that provides a namespace'
|
||||
)
|
||||
warnings.warn(
|
||||
'Passing a 3-tuple to django.conf.urls.include() is deprecated. '
|
||||
'Pass a 2-tuple containing the list of patterns and app_name, '
|
||||
'and provide the namespace argument to include() instead.',
|
||||
RemovedInDjango21Warning, stacklevel=2
|
||||
)
|
||||
urlconf_module, app_name, namespace = arg
|
||||
else:
|
||||
# No namespace hint - use manually provided namespace
|
||||
|
@ -32,6 +49,17 @@ def include(arg, namespace=None, app_name=None):
|
|||
if isinstance(urlconf_module, six.string_types):
|
||||
urlconf_module = import_module(urlconf_module)
|
||||
patterns = getattr(urlconf_module, 'urlpatterns', urlconf_module)
|
||||
app_name = getattr(urlconf_module, 'app_name', app_name)
|
||||
if namespace and not app_name:
|
||||
warnings.warn(
|
||||
'Specifying a namespace in django.conf.urls.include() without '
|
||||
'providing an app_name is deprecated. Set the app_name attribute '
|
||||
'in the included module, or pass a 2-tuple containing the list of '
|
||||
'patterns and app_name instead.',
|
||||
RemovedInDjango21Warning, stacklevel=2
|
||||
)
|
||||
|
||||
namespace = namespace or app_name
|
||||
|
||||
# Make sure we can iterate through the patterns (without this, some
|
||||
# testcases will break).
|
||||
|
|
|
@ -70,6 +70,15 @@ details on these changes.
|
|||
``django.utils.feedgenerator.RssFeed`` will be removed in favor of
|
||||
``content_type``.
|
||||
|
||||
* The ``app_name`` argument to :func:`~django.conf.urls.include()` will be
|
||||
removed.
|
||||
|
||||
* Support for passing a 3-tuple as the first argument to ``include()`` will
|
||||
be removed.
|
||||
|
||||
* Support for setting a URL instance namespace without an application
|
||||
namespace will be removed.
|
||||
|
||||
.. _deprecation-removed-in-2.0:
|
||||
|
||||
2.0
|
||||
|
|
|
@ -293,15 +293,15 @@ with:
|
|||
|
||||
urlpatterns = [
|
||||
url(r'^polls/', include('polls.urls')),
|
||||
url(r'^admin/', include(admin.site.urls)),
|
||||
url(r'^admin/', admin.site.urls),
|
||||
]
|
||||
|
||||
.. admonition:: Doesn't match what you see?
|
||||
|
||||
If you're seeing ``admin.autodiscover()`` before the definition of
|
||||
``urlpatterns``, you're probably using a version of Django that doesn't
|
||||
match this tutorial version. You'll want to either switch to the older
|
||||
tutorial or the newer Django version.
|
||||
If you're seeing ``include(admin.site.urls)`` instead of just
|
||||
``admin.site.urls``, you're probably using a version of Django that
|
||||
doesn't match this tutorial version. You'll want to either switch to the
|
||||
older tutorial or the newer Django version.
|
||||
|
||||
You have now wired an ``index`` view into the URLconf. Lets verify it's
|
||||
working, run the following command:
|
||||
|
|
|
@ -442,18 +442,20 @@ view, and so might an app on the same project that is for a blog. How does one
|
|||
make it so that Django knows which app view to create for a url when using the
|
||||
``{% url %}`` template tag?
|
||||
|
||||
The answer is to add namespaces to your root URLconf. In the ``mysite/urls.py``
|
||||
file, go ahead and change it to include namespacing:
|
||||
The answer is to add namespaces to your URLconf. In the ``polls/urls.py``
|
||||
file, go ahead and add an ``app_name`` to set the application namespace:
|
||||
|
||||
.. snippet::
|
||||
:filename: mysite/urls.py
|
||||
:filename: polls/urls.py
|
||||
|
||||
from django.conf.urls import include, url
|
||||
from django.contrib import admin
|
||||
from django.conf.urls import url
|
||||
|
||||
app_name = 'polls'
|
||||
urlpatterns = [
|
||||
url(r'^polls/', include('polls.urls', namespace="polls")),
|
||||
url(r'^admin/', include(admin.site.urls)),
|
||||
url(r'^$', views.index, name='index'),
|
||||
url(r'^(?P<question_id>[0-9]+)/$', views.detail, name='detail'),
|
||||
url(r'^(?P<question_id>[0-9]+)/results/$', views.results, name='results'),
|
||||
url(r'^(?P<question_id>[0-9]+)/vote/$', views.vote, name='vote'),
|
||||
]
|
||||
|
||||
Now change your ``polls/index.html`` template from:
|
||||
|
|
|
@ -2613,19 +2613,25 @@ Hooking ``AdminSite`` instances into your URLconf
|
|||
|
||||
The last step in setting up the Django admin is to hook your ``AdminSite``
|
||||
instance into your URLconf. Do this by pointing a given URL at the
|
||||
``AdminSite.urls`` method.
|
||||
``AdminSite.urls`` method. It is not necessary to use
|
||||
:func:`~django.conf.urls.include()`.
|
||||
|
||||
In this example, we register the default ``AdminSite`` instance
|
||||
``django.contrib.admin.site`` at the URL ``/admin/`` ::
|
||||
|
||||
# urls.py
|
||||
from django.conf.urls import include, url
|
||||
from django.conf.urls import url
|
||||
from django.contrib import admin
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^admin/', include(admin.site.urls)),
|
||||
url(r'^admin/', admin.site.urls),
|
||||
]
|
||||
|
||||
.. versionchanged:: 1.9
|
||||
|
||||
In previous versions, you would pass ``admin.site.urls`` to
|
||||
:func:`~django.conf.urls.include()`.
|
||||
|
||||
.. _customizing-adminsite:
|
||||
|
||||
Customizing the :class:`AdminSite` class
|
||||
|
@ -2655,12 +2661,12 @@ update :file:`myproject/urls.py` to reference your :class:`AdminSite` subclass.
|
|||
.. snippet::
|
||||
:filename: myproject/urls.py
|
||||
|
||||
from django.conf.urls import include, url
|
||||
from django.conf.urls import url
|
||||
|
||||
from myapp.admin import admin_site
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^myadmin/', include(admin_site.urls)),
|
||||
url(r'^myadmin/', admin_site.urls),
|
||||
]
|
||||
|
||||
Note that you may not want autodiscovery of ``admin`` modules when using your
|
||||
|
@ -2684,12 +2690,12 @@ separate versions of the admin site -- using the ``AdminSite`` instances
|
|||
respectively::
|
||||
|
||||
# urls.py
|
||||
from django.conf.urls import include, url
|
||||
from django.conf.urls import url
|
||||
from myproject.admin import basic_site, advanced_site
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^basic-admin/', include(basic_site.urls)),
|
||||
url(r'^advanced-admin/', include(advanced_site.urls)),
|
||||
url(r'^basic-admin/', basic_site.urls),
|
||||
url(r'^advanced-admin/', advanced_site.urls),
|
||||
]
|
||||
|
||||
``AdminSite`` instances take a single argument to their constructor, their
|
||||
|
|
|
@ -749,7 +749,7 @@ Next, edit your ``urls.py`` in the ``geodjango`` application folder as follows::
|
|||
from django.contrib.gis import admin
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^admin/', include(admin.site.urls)),
|
||||
url(r'^admin/', admin.site.urls),
|
||||
]
|
||||
|
||||
Create an admin user:
|
||||
|
|
|
@ -130,6 +130,7 @@ include()
|
|||
|
||||
.. function:: include(module[, namespace=None, app_name=None])
|
||||
include(pattern_list)
|
||||
include((pattern_list, app_namespace)[, namespace=None])
|
||||
include((pattern_list, app_namespace, instance_namespace))
|
||||
|
||||
A function that takes a full Python import path to another URLconf module
|
||||
|
@ -137,9 +138,14 @@ include()
|
|||
namespace` and :term:`instance namespace` where the entries will be included
|
||||
into can also be specified.
|
||||
|
||||
Usually, the application namespace should be specified by the included
|
||||
module. If an application namespace is set, the ``namespace`` argument
|
||||
can be used to set a different instance namespace.
|
||||
|
||||
``include()`` also accepts as an argument either an iterable that returns
|
||||
URL patterns or a 3-tuple containing such iterable plus the names of the
|
||||
application and instance namespaces.
|
||||
URL patterns, a 2-tuple containing such iterable plus the names of the
|
||||
application namespaces, or a 3-tuple containing the iterable and the names
|
||||
of both the application and instance namespace.
|
||||
|
||||
:arg module: URLconf module (or module name)
|
||||
:arg namespace: Instance namespace for the URL entries being included
|
||||
|
@ -154,6 +160,20 @@ include()
|
|||
|
||||
See :ref:`including-other-urlconfs` and :ref:`namespaces-and-include`.
|
||||
|
||||
.. deprecated:: 1.9
|
||||
|
||||
Support for the ``app_name`` argument is deprecated and will be removed in
|
||||
Django 2.1. Specify the ``app_name`` as explained in
|
||||
:ref:`namespaces-and-include` instead.
|
||||
|
||||
Support for passing a 3-tuple is also deprecated and will be removed in
|
||||
Django 2.1. Pass a 2-tuple containing the pattern list and application
|
||||
namespace, and use the ``namespace`` argument instead.
|
||||
|
||||
Lastly, support for an instance namespace without an application namespace
|
||||
has been deprecated and will be removed in Django 2.1. Specify the
|
||||
application namespace or remove the instance namespace.
|
||||
|
||||
handler400
|
||||
----------
|
||||
|
||||
|
|
|
@ -385,6 +385,11 @@ URLs
|
|||
|
||||
* Regular expression lookaround assertions are now allowed in URL patterns.
|
||||
|
||||
* The application namespace can now be set using an ``app_name`` attribute
|
||||
on the included module or object. It can also be set by passing a 2-tuple
|
||||
of (<list of patterns>, <application namespace>) as the first argument to
|
||||
:func:`~django.conf.urls.include`.
|
||||
|
||||
Validators
|
||||
^^^^^^^^^^
|
||||
|
||||
|
@ -706,6 +711,40 @@ extending. This change necessitated a new template loader API. The old
|
|||
Details about the new API can be found :ref:`in the template loader
|
||||
documentation <custom-template-loaders>`.
|
||||
|
||||
Passing a 3-tuple or an ``app_name`` to :func:`~django.conf.urls.include()`
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The instance namespace part of passing a tuple as the first argument has been
|
||||
replaced by passing the ``namespace`` argument to ``include()``. The
|
||||
``app_name`` argument to ``include()`` has been replaced by passing a 2-tuple,
|
||||
or passing an object or module with an ``app_name`` attribute.
|
||||
|
||||
If the ``app_name`` is set in this new way, the ``namespace`` argument is no
|
||||
longer required. It will default to the value of ``app_name``.
|
||||
|
||||
This change also means that the old way of including an ``AdminSite`` instance
|
||||
is deprecated. Instead, pass ``admin.site.urls`` directly to
|
||||
:func:`~django.conf.urls.url()`:
|
||||
|
||||
.. snippet::
|
||||
:filename: urls.py
|
||||
|
||||
from django.conf.urls import url
|
||||
from django.contrib import admin
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^admin/', admin.site.urls),
|
||||
]
|
||||
|
||||
URL application namespace required if setting an instance namespace
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
In the past, an instance namespace without an application namespace
|
||||
would serve the same purpose as the application namespace, but it was
|
||||
impossible to reverse the patterns if there was an application namespace
|
||||
with the same name. Includes that specify an instance namespace require that
|
||||
the included URLconf sets an application namespace.
|
||||
|
||||
Miscellaneous
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
|
|
|
@ -716,8 +716,8 @@ displaying polls.
|
|||
from django.conf.urls import include, url
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^author-polls/', include('polls.urls', namespace='author-polls', app_name='polls')),
|
||||
url(r'^publisher-polls/', include('polls.urls', namespace='publisher-polls', app_name='polls')),
|
||||
url(r'^author-polls/', include('polls.urls', namespace='author-polls')),
|
||||
url(r'^publisher-polls/', include('polls.urls', namespace='publisher-polls')),
|
||||
]
|
||||
|
||||
.. snippet::
|
||||
|
@ -727,6 +727,7 @@ displaying polls.
|
|||
|
||||
from . import views
|
||||
|
||||
app_name = 'polls'
|
||||
urlpatterns = [
|
||||
url(r'^$', views.IndexView.as_view(), name='index'),
|
||||
url(r'^(?P<pk>\d+)/$', views.DetailView.as_view(), name='detail'),
|
||||
|
@ -778,25 +779,44 @@ declared last in ``urlpatterns``.
|
|||
URL namespaces and included URLconfs
|
||||
------------------------------------
|
||||
|
||||
URL namespaces of included URLconfs can be specified in two ways.
|
||||
Application namespaces of included URLconfs can be specified in two ways.
|
||||
|
||||
Firstly, you can provide the :term:`application <application namespace>` and
|
||||
:term:`instance <instance namespace>` namespaces as arguments to
|
||||
:func:`~django.conf.urls.include()` when you construct your URL patterns. For
|
||||
example,::
|
||||
Firstly, you can set an ``app_name`` attribute in the included URLconf module,
|
||||
at the same level as the ``urlpatterns`` attribute. You have to pass the actual
|
||||
module, or a string reference to the module, to
|
||||
:func:`~django.conf.urls.include`, not the list of ``urlpatterns`` itself.
|
||||
|
||||
url(r'^polls/', include('polls.urls', namespace='author-polls', app_name='polls')),
|
||||
.. snippet::
|
||||
:filename: polls/urls.py
|
||||
|
||||
This will include the URLs defined in ``polls.urls`` into the
|
||||
:term:`application namespace` ``'polls'``, with the :term:`instance namespace`
|
||||
``'author-polls'``.
|
||||
from django.conf.urls import url
|
||||
|
||||
from . import views
|
||||
|
||||
app_name = 'polls'
|
||||
urlpatterns = [
|
||||
url(r'^$', views.IndexView.as_view(), name='index'),
|
||||
url(r'^(?P<pk>\d+)/$', views.DetailView.as_view(), name='detail'),
|
||||
...
|
||||
]
|
||||
|
||||
.. snippet::
|
||||
:filename: urls.py
|
||||
|
||||
from django.conf.urls import include, url
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^polls/', include('polls.urls')),
|
||||
]
|
||||
|
||||
The URLs defined in ``polls.urls`` will have an application namespace ``polls``.
|
||||
|
||||
Secondly, you can include an object that contains embedded namespace data. If
|
||||
you ``include()`` a list of :func:`~django.conf.urls.url` instances,
|
||||
the URLs contained in that object will be added to the global namespace.
|
||||
However, you can also ``include()`` a 3-tuple containing::
|
||||
However, you can also ``include()`` a 2-tuple containing::
|
||||
|
||||
(<list of url() instances>, <application namespace>, <instance namespace>)
|
||||
(<list of url() instances>, <application namespace>)
|
||||
|
||||
For example::
|
||||
|
||||
|
@ -804,25 +824,25 @@ For example::
|
|||
|
||||
from . import views
|
||||
|
||||
polls_patterns = [
|
||||
polls_patterns = ([
|
||||
url(r'^$', views.IndexView.as_view(), name='index'),
|
||||
url(r'^(?P<pk>\d+)/$', views.DetailView.as_view(), name='detail'),
|
||||
]
|
||||
], 'polls')
|
||||
|
||||
url(r'^polls/', include((polls_patterns, 'polls', 'author-polls'))),
|
||||
url(r'^polls/', include(polls_patterns)),
|
||||
|
||||
This will include the nominated URL patterns into the given application and
|
||||
instance namespace.
|
||||
This will include the nominated URL patterns into the given application
|
||||
namespace.
|
||||
|
||||
For example, the Django admin is deployed as instances of
|
||||
:class:`~django.contrib.admin.AdminSite`. ``AdminSite`` objects have a ``urls``
|
||||
attribute: A 3-tuple that contains all the patterns in the corresponding admin
|
||||
site, plus the application namespace ``'admin'``, and the name of the admin
|
||||
instance. It is this ``urls`` attribute that you ``include()`` into your
|
||||
projects ``urlpatterns`` when you deploy an admin instance.
|
||||
The instance namespace can be specified using the ``namespace`` argument to
|
||||
:func:`~django.conf.urls.include`. If the instance namespace is not specified,
|
||||
it will default to the included URLconf's application namespace. This means
|
||||
it will also be the default instance for that namespace.
|
||||
|
||||
Be sure to pass a tuple to ``include()``. If you simply pass three arguments:
|
||||
``include(polls_patterns, 'polls', 'author-polls')``, Django won't throw an
|
||||
error but due to the signature of ``include()``, ``'polls'`` will be the
|
||||
instance namespace and ``'author-polls'`` will be the application namespace
|
||||
instead of vice versa.
|
||||
.. versionchanged:: 1.9
|
||||
|
||||
In previous versions, you had to specify both the application namespace
|
||||
and the instance namespace in a single place, either by passing them as
|
||||
parameters to :func:`~django.conf.urls.include` or by including a 3-tuple
|
||||
containing
|
||||
``(<list of url() instances>, <application namespace>, <instance namespace>)``.
|
||||
|
|
|
@ -1285,11 +1285,11 @@ prepend the current active language code to all url patterns defined within
|
|||
url(r'^sitemap\.xml$', sitemap, name='sitemap_xml'),
|
||||
]
|
||||
|
||||
news_patterns = [
|
||||
news_patterns = ([
|
||||
url(r'^$', news_views.index, name='index'),
|
||||
url(r'^category/(?P<slug>[\w-]+)/$', news_views.category, name='category'),
|
||||
url(r'^(?P<slug>[\w-]+)/$', news_views.details, name='detail'),
|
||||
]
|
||||
], 'news')
|
||||
|
||||
urlpatterns += i18n_patterns(
|
||||
url(r'^about/$', about_views.main, name='about'),
|
||||
|
@ -1343,11 +1343,11 @@ URL patterns can also be marked translatable using the
|
|||
url(r'^sitemap\.xml$', sitemap, name='sitemap_xml'),
|
||||
]
|
||||
|
||||
news_patterns = [
|
||||
news_patterns = ([
|
||||
url(r'^$', news_views.index, name='index'),
|
||||
url(_(r'^category/(?P<slug>[\w-]+)/$'), news_views.category, name='category'),
|
||||
url(r'^(?P<slug>[\w-]+)/$', news_views.details, name='detail'),
|
||||
]
|
||||
], 'news')
|
||||
|
||||
urlpatterns += i18n_patterns(
|
||||
url(_(r'^about/$'), about_views.main, name='about'),
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
from django.conf.urls import include, url
|
||||
from django.conf.urls import url
|
||||
|
||||
from . import admin
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^admin/', include(admin.site.urls)),
|
||||
url(r'^admin/', admin.site.urls),
|
||||
]
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
from django.conf.urls import include, url
|
||||
from django.conf.urls import url
|
||||
|
||||
from .models import site
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^admin/', include(site.urls)),
|
||||
url(r'^admin/', site.urls),
|
||||
]
|
||||
|
|
|
@ -3,12 +3,12 @@ from django.contrib import admin
|
|||
|
||||
from . import views
|
||||
|
||||
ns_patterns = [
|
||||
ns_patterns = ([
|
||||
url(r'^xview/func/$', views.xview_dec(views.xview), name='func'),
|
||||
]
|
||||
], 'test')
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^admin/', include(admin.site.urls)),
|
||||
url(r'^admin/', admin.site.urls),
|
||||
url(r'^admindocs/', include('django.contrib.admindocs.urls')),
|
||||
url(r'^', include(ns_patterns, namespace='test')),
|
||||
url(r'^xview/func/$', views.xview_dec(views.xview)),
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
from django.conf.urls import include, url
|
||||
from django.conf.urls import url
|
||||
|
||||
from . import admin
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^admin/', include(admin.site.urls)),
|
||||
url(r'^admin/', admin.site.urls),
|
||||
]
|
||||
|
|
|
@ -2,7 +2,7 @@ from __future__ import unicode_literals
|
|||
|
||||
import datetime
|
||||
|
||||
from django.conf.urls import include, url
|
||||
from django.conf.urls import url
|
||||
from django.contrib import admin
|
||||
from django.contrib.auth.models import User
|
||||
from django.core.urlresolvers import reverse
|
||||
|
@ -16,7 +16,7 @@ site.register(User)
|
|||
site.register(Article)
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^test_admin/admin/', include(site.urls)),
|
||||
url(r'^test_admin/admin/', site.urls),
|
||||
]
|
||||
|
||||
|
||||
|
|
|
@ -6,11 +6,11 @@ urlpatterns = [
|
|||
url(r'^test_admin/admin/doc/', include('django.contrib.admindocs.urls')),
|
||||
url(r'^test_admin/admin/secure-view/$', views.secure_view, name='secure_view'),
|
||||
url(r'^test_admin/admin/secure-view2/$', views.secure_view2, name='secure_view2'),
|
||||
url(r'^test_admin/admin/', include(admin.site.urls)),
|
||||
url(r'^test_admin/admin2/', include(customadmin.site.urls)),
|
||||
url(r'^test_admin/admin3/', include(admin.site.get_urls(), 'admin3', 'admin'), dict(form_url='pony')),
|
||||
url(r'^test_admin/admin4/', include(customadmin.simple_site.urls)),
|
||||
url(r'^test_admin/admin5/', include(admin.site2.urls)),
|
||||
url(r'^test_admin/admin7/', include(admin.site7.urls)),
|
||||
url(r'^test_admin/has_permission_admin/', include(custom_has_permission_admin.site.urls)),
|
||||
url(r'^test_admin/admin/', admin.site.urls),
|
||||
url(r'^test_admin/admin2/', customadmin.site.urls),
|
||||
url(r'^test_admin/admin3/', (admin.site.get_urls(), 'admin', 'admin3'), dict(form_url='pony')),
|
||||
url(r'^test_admin/admin4/', customadmin.simple_site.urls),
|
||||
url(r'^test_admin/admin5/', admin.site2.urls),
|
||||
url(r'^test_admin/admin7/', admin.site7.urls),
|
||||
url(r'^test_admin/has_permission_admin/', custom_has_permission_admin.site.urls),
|
||||
]
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
from django.conf.urls import include, url
|
||||
from django.conf.urls import url
|
||||
|
||||
from . import widgetadmin
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^', include(widgetadmin.site.urls)),
|
||||
url(r'^', widgetadmin.site.urls),
|
||||
]
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from django.conf.urls import include, url
|
||||
from django.conf.urls import url
|
||||
from django.contrib import admin
|
||||
from django.contrib.auth import views
|
||||
from django.contrib.auth.decorators import login_required
|
||||
|
@ -97,5 +97,5 @@ urlpatterns = auth_urlpatterns + [
|
|||
url(r'^userpage/(.+)/$', userpage, name="userpage"),
|
||||
|
||||
# This line is only required to render the password reset with is_admin=True
|
||||
url(r'^admin/', include(admin.site.urls)),
|
||||
url(r'^admin/', admin.site.urls),
|
||||
]
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
Test URLs for auth admins.
|
||||
"""
|
||||
|
||||
from django.conf.urls import include, url
|
||||
from django.conf.urls import url
|
||||
from django.contrib import admin
|
||||
from django.contrib.auth.admin import GroupAdmin, UserAdmin
|
||||
from django.contrib.auth.models import Group, User
|
||||
|
@ -14,5 +14,5 @@ site.register(User, UserAdmin)
|
|||
site.register(Group, GroupAdmin)
|
||||
|
||||
urlpatterns += [
|
||||
url(r'^admin/', include(site.urls)),
|
||||
url(r'^admin/', site.urls),
|
||||
]
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from django.conf.urls import include, url
|
||||
from django.conf.urls import url
|
||||
from django.contrib import admin
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.contrib.auth.admin import UserAdmin
|
||||
|
@ -16,5 +16,5 @@ class CustomUserAdmin(UserAdmin):
|
|||
site.register(get_user_model(), CustomUserAdmin)
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^admin/', include(site.urls)),
|
||||
url(r'^admin/', site.urls),
|
||||
]
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
from django.conf.urls import include, url
|
||||
from django.conf.urls import url
|
||||
|
||||
from . import admin
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^generic_inline_admin/admin/', include(admin.site.urls)),
|
||||
url(r'^generic_inline_admin/admin/', admin.site.urls),
|
||||
]
|
||||
|
|
|
@ -4,6 +4,7 @@ from django.views.generic import TemplateView
|
|||
|
||||
view = TemplateView.as_view(template_name='dummy.html')
|
||||
|
||||
app_name = 'account'
|
||||
urlpatterns = [
|
||||
url(_(r'^register/$'), view, name='register'),
|
||||
url(_(r'^register-without-slash$'), view, name='register-without-slash'),
|
||||
|
|
|
@ -5,6 +5,7 @@ from django.views.generic import TemplateView
|
|||
|
||||
view = TemplateView.as_view(template_name='dummy.html')
|
||||
|
||||
app_name = 'account'
|
||||
urlpatterns = i18n_patterns(
|
||||
url(_(r'^register/$'), view, name='register'),
|
||||
)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
from django.conf.urls import include, url
|
||||
from django.conf.urls import url
|
||||
|
||||
from .admin import site
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^admin/', include(site.urls)),
|
||||
url(r'^admin/', site.urls),
|
||||
]
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
from django.conf.urls import include, url
|
||||
from django.conf.urls import url
|
||||
|
||||
from . import admin as tz_admin # NOQA: register tz_admin
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^admin/', include(tz_admin.site.urls)),
|
||||
url(r'^admin/', tz_admin.site.urls),
|
||||
]
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
from django.conf.urls import url
|
||||
|
||||
from . import views
|
||||
|
||||
app_name = 'inc-app'
|
||||
urlpatterns = [
|
||||
url(r'^normal/$', views.empty_view, name='inc-normal-view'),
|
||||
url(r'^normal/(?P<arg1>[0-9]+)/(?P<arg2>[0-9]+)/$', views.empty_view, name='inc-normal-view'),
|
||||
|
||||
url(r'^\+\\\$\*/$', views.empty_view, name='inc-special-view'),
|
||||
|
||||
url(r'^mixed_args/([0-9]+)/(?P<arg2>[0-9]+)/$', views.empty_view, name='inc-mixed-args'),
|
||||
url(r'^no_kwargs/([0-9]+)/([0-9]+)/$', views.empty_view, name='inc-no-kwargs'),
|
||||
|
||||
url(r'^view_class/(?P<arg1>[0-9]+)/(?P<arg2>[0-9]+)/$', views.view_class_instance, name='inc-view-class'),
|
||||
]
|
|
@ -1,20 +1,7 @@
|
|||
from django.conf.urls import include, url
|
||||
|
||||
from . import views
|
||||
|
||||
|
||||
class URLObject(object):
|
||||
def __init__(self, app_name, namespace):
|
||||
self.app_name = app_name
|
||||
self.namespace = namespace
|
||||
|
||||
def urls(self):
|
||||
return ([
|
||||
url(r'^inner/$', 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/\+\\\$\*/$', views.empty_view, name='urlobject-special-view'),
|
||||
], self.app_name, self.namespace)
|
||||
urls = property(urls)
|
||||
from .tests import URLObject
|
||||
|
||||
testobj1 = URLObject('testapp', 'test-ns1')
|
||||
testobj2 = URLObject('testapp', 'test-ns2')
|
||||
|
@ -23,6 +10,8 @@ default_testobj = URLObject('testapp', 'testapp')
|
|||
otherobj1 = URLObject('nodefault', 'other-ns1')
|
||||
otherobj2 = URLObject('nodefault', 'other-ns2')
|
||||
|
||||
newappobj1 = URLObject('newapp')
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^normal/$', views.empty_view, name='normal-view'),
|
||||
url(r'^normal/(?P<arg1>[0-9]+)/(?P<arg2>[0-9]+)/$', views.empty_view, name='normal-view'),
|
||||
|
@ -45,6 +34,12 @@ urlpatterns = [
|
|||
url(r'^other1/', include(otherobj1.urls)),
|
||||
url(r'^other[246]/', include(otherobj2.urls)),
|
||||
|
||||
url(r'^newapp1/', include(newappobj1.app_urls, 'new-ns1')),
|
||||
url(r'^new-default/', include(newappobj1.app_urls)),
|
||||
|
||||
url(r'^app-included[135]/', include('urlpatterns_reverse.included_app_urls', namespace='app-ns1')),
|
||||
url(r'^app-included2/', include('urlpatterns_reverse.included_app_urls', namespace='app-ns2')),
|
||||
|
||||
url(r'^ns-included[135]/', include('urlpatterns_reverse.included_namespace_urls', namespace='inc-ns1')),
|
||||
url(r'^ns-included2/', include('urlpatterns_reverse.included_namespace_urls', namespace='inc-ns2')),
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ import unittest
|
|||
from admin_scripts.tests import AdminScriptTestCase
|
||||
|
||||
from django.conf import settings
|
||||
from django.conf.urls import include
|
||||
from django.conf.urls import include, url
|
||||
from django.contrib.auth.models import User
|
||||
from django.core.exceptions import ImproperlyConfigured, ViewDoesNotExist
|
||||
from django.core.urlresolvers import (
|
||||
|
@ -26,7 +26,9 @@ from django.test import (
|
|||
)
|
||||
from django.test.utils import override_script_prefix
|
||||
from django.utils import six
|
||||
from django.utils.deprecation import RemovedInDjango20Warning
|
||||
from django.utils.deprecation import (
|
||||
RemovedInDjango20Warning, RemovedInDjango21Warning,
|
||||
)
|
||||
|
||||
from . import middleware, urlconf_outer, views
|
||||
from .views import empty_view
|
||||
|
@ -184,6 +186,26 @@ test_data = (
|
|||
)
|
||||
|
||||
|
||||
class URLObject(object):
|
||||
urlpatterns = [
|
||||
url(r'^inner/$', 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/\+\\\$\*/$', views.empty_view, name='urlobject-special-view'),
|
||||
]
|
||||
|
||||
def __init__(self, app_name, namespace=None):
|
||||
self.app_name = app_name
|
||||
self.namespace = namespace
|
||||
|
||||
@property
|
||||
def urls(self):
|
||||
return self.urlpatterns, self.app_name, self.namespace
|
||||
|
||||
@property
|
||||
def app_urls(self):
|
||||
return self.urlpatterns, self.app_name
|
||||
|
||||
|
||||
@override_settings(ROOT_URLCONF='urlpatterns_reverse.no_urls')
|
||||
class NoURLPatternsTests(SimpleTestCase):
|
||||
|
||||
|
@ -281,6 +303,7 @@ class URLPatternReverse(SimpleTestCase):
|
|||
|
||||
|
||||
class ResolverTests(unittest.TestCase):
|
||||
@ignore_warnings(category=RemovedInDjango21Warning)
|
||||
def test_resolver_repr(self):
|
||||
"""
|
||||
Test repr of RegexURLResolver, especially when urlconf_name is a list
|
||||
|
@ -460,6 +483,7 @@ class ReverseShortcutTests(SimpleTestCase):
|
|||
|
||||
|
||||
@override_settings(ROOT_URLCONF='urlpatterns_reverse.namespace_urls')
|
||||
@ignore_warnings(category=RemovedInDjango21Warning)
|
||||
class NamespaceTests(SimpleTestCase):
|
||||
|
||||
def test_ambiguous_object(self):
|
||||
|
@ -500,6 +524,20 @@ class NamespaceTests(SimpleTestCase):
|
|||
self.assertEqual('/test1/inner/42/37/', reverse('test-ns1:urlobject-view', kwargs={'arg1': 42, 'arg2': 37}))
|
||||
self.assertEqual('/test1/inner/+%5C$*/', reverse('test-ns1:urlobject-special-view'))
|
||||
|
||||
def test_app_object(self):
|
||||
"Dynamic URL objects can return a (pattern, app_name) 2-tuple, and include() can set the namespace"
|
||||
self.assertEqual('/newapp1/inner/', reverse('new-ns1:urlobject-view'))
|
||||
self.assertEqual('/newapp1/inner/37/42/', reverse('new-ns1:urlobject-view', args=[37, 42]))
|
||||
self.assertEqual('/newapp1/inner/42/37/', reverse('new-ns1:urlobject-view', kwargs={'arg1': 42, 'arg2': 37}))
|
||||
self.assertEqual('/newapp1/inner/+%5C$*/', reverse('new-ns1:urlobject-special-view'))
|
||||
|
||||
def test_app_object_default_namespace(self):
|
||||
"Namespace defaults to app_name when including a (pattern, app_name) 2-tuple"
|
||||
self.assertEqual('/new-default/inner/', reverse('newapp:urlobject-view'))
|
||||
self.assertEqual('/new-default/inner/37/42/', reverse('newapp:urlobject-view', args=[37, 42]))
|
||||
self.assertEqual('/new-default/inner/42/37/', reverse('newapp:urlobject-view', kwargs={'arg1': 42, 'arg2': 37}))
|
||||
self.assertEqual('/new-default/inner/+%5C$*/', reverse('newapp:urlobject-special-view'))
|
||||
|
||||
def test_embedded_namespace_object(self):
|
||||
"Namespaces can be installed anywhere in the URL pattern tree"
|
||||
self.assertEqual('/included/test3/inner/', reverse('test-ns3:urlobject-view'))
|
||||
|
@ -514,6 +552,13 @@ class NamespaceTests(SimpleTestCase):
|
|||
self.assertEqual('/ns-included1/normal/42/37/', reverse('inc-ns1:inc-normal-view', kwargs={'arg1': 42, 'arg2': 37}))
|
||||
self.assertEqual('/ns-included1/+%5C$*/', reverse('inc-ns1:inc-special-view'))
|
||||
|
||||
def test_app_name_pattern(self):
|
||||
"Namespaces can be applied to include()'d urlpatterns that set an app_name attribute"
|
||||
self.assertEqual('/app-included1/normal/', reverse('app-ns1:inc-normal-view'))
|
||||
self.assertEqual('/app-included1/normal/37/42/', reverse('app-ns1:inc-normal-view', args=[37, 42]))
|
||||
self.assertEqual('/app-included1/normal/42/37/', reverse('app-ns1:inc-normal-view', kwargs={'arg1': 42, 'arg2': 37}))
|
||||
self.assertEqual('/app-included1/+%5C$*/', reverse('app-ns1:inc-special-view'))
|
||||
|
||||
def test_namespace_pattern_with_variable_prefix(self):
|
||||
"When using an include with namespaces when there is a regex variable in front of it"
|
||||
self.assertEqual('/ns-outer/42/normal/', reverse('inc-outer:inc-normal-view', kwargs={'outer': 42}))
|
||||
|
@ -769,6 +814,7 @@ class NoRootUrlConfTests(SimpleTestCase):
|
|||
@override_settings(ROOT_URLCONF='urlpatterns_reverse.namespace_urls')
|
||||
class ResolverMatchTests(SimpleTestCase):
|
||||
|
||||
@ignore_warnings(category=RemovedInDjango21Warning)
|
||||
def test_urlpattern_resolve(self):
|
||||
for path, url_name, app_name, namespace, view_name, func, args, kwargs in resolve_test_data:
|
||||
# Test legacy support for extracting "function, args, kwargs"
|
||||
|
@ -793,6 +839,7 @@ class ResolverMatchTests(SimpleTestCase):
|
|||
self.assertEqual(match[1], args)
|
||||
self.assertEqual(match[2], kwargs)
|
||||
|
||||
@ignore_warnings(category=RemovedInDjango21Warning)
|
||||
def test_resolver_match_on_request(self):
|
||||
response = self.client.get('/resolver_match/')
|
||||
resolver_match = response.resolver_match
|
||||
|
@ -845,10 +892,65 @@ class ViewLoadingTests(SimpleTestCase):
|
|||
|
||||
|
||||
class IncludeTests(SimpleTestCase):
|
||||
url_patterns = [
|
||||
url(r'^inner/$', 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/\+\\\$\*/$', views.empty_view, name='urlobject-special-view'),
|
||||
]
|
||||
app_urls = URLObject('inc-app')
|
||||
|
||||
def test_include_app_name_but_no_namespace(self):
|
||||
msg = "Must specify a namespace if specifying app_name."
|
||||
with self.assertRaisesMessage(ValueError, msg):
|
||||
include('urls', app_name='bar')
|
||||
include(self.url_patterns, app_name='bar')
|
||||
|
||||
def test_include_urls(self):
|
||||
self.assertEqual(include(self.url_patterns), (self.url_patterns, None, None))
|
||||
|
||||
@ignore_warnings(category=RemovedInDjango21Warning)
|
||||
def test_include_namespace(self):
|
||||
# no app_name -> deprecated
|
||||
self.assertEqual(include(self.url_patterns, 'namespace'), (self.url_patterns, None, 'namespace'))
|
||||
|
||||
@ignore_warnings(category=RemovedInDjango21Warning)
|
||||
def test_include_namespace_app_name(self):
|
||||
# app_name argument to include -> deprecated
|
||||
self.assertEqual(
|
||||
include(self.url_patterns, 'namespace', 'app_name'),
|
||||
(self.url_patterns, 'app_name', 'namespace')
|
||||
)
|
||||
|
||||
@ignore_warnings(category=RemovedInDjango21Warning)
|
||||
def test_include_3_tuple(self):
|
||||
# 3-tuple -> deprecated
|
||||
self.assertEqual(
|
||||
include((self.url_patterns, 'app_name', 'namespace')),
|
||||
(self.url_patterns, 'app_name', 'namespace')
|
||||
)
|
||||
|
||||
def test_include_2_tuple(self):
|
||||
self.assertEqual(
|
||||
include((self.url_patterns, 'app_name')),
|
||||
(self.url_patterns, 'app_name', 'app_name')
|
||||
)
|
||||
|
||||
def test_include_2_tuple_namespace(self):
|
||||
self.assertEqual(
|
||||
include((self.url_patterns, 'app_name'), namespace='namespace'),
|
||||
(self.url_patterns, 'app_name', 'namespace')
|
||||
)
|
||||
|
||||
def test_include_app_name(self):
|
||||
self.assertEqual(
|
||||
include(self.app_urls),
|
||||
(self.app_urls, 'inc-app', 'inc-app')
|
||||
)
|
||||
|
||||
def test_include_app_name_namespace(self):
|
||||
self.assertEqual(
|
||||
include(self.app_urls, 'namespace'),
|
||||
(self.app_urls, 'inc-app', 'namespace')
|
||||
)
|
||||
|
||||
|
||||
@override_settings(ROOT_URLCONF='urlpatterns_reverse.urls')
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
from django.conf.urls import include, url
|
||||
from django.conf.urls import url
|
||||
from django.contrib import admin
|
||||
|
||||
urlpatterns = [
|
||||
# This is the same as in the default project template
|
||||
url(r'^admin/', include(admin.site.urls)),
|
||||
url(r'^admin/', admin.site.urls),
|
||||
]
|
||||
|
|
Loading…
Reference in New Issue