mirror of
https://github.com/django/django.git
synced 2024-12-22 17:16:24 +00:00
Refs #22384 -- Removed the ability to reverse URLs by dotted path per deprecation timeline.
This commit is contained in:
parent
d79122f40b
commit
785cc71d5b
@ -79,5 +79,7 @@ def url(regex, view, kwargs=None, name=None):
|
||||
# For include(...) processing.
|
||||
urlconf_module, app_name, namespace = view
|
||||
return RegexURLResolver(regex, urlconf_module, kwargs, app_name=app_name, namespace=namespace)
|
||||
else:
|
||||
elif callable(view):
|
||||
return RegexURLPattern(regex, view, kwargs, name)
|
||||
else:
|
||||
raise TypeError('view must be a callable or a list/tuple in the case of include().')
|
||||
|
@ -9,7 +9,6 @@ from __future__ import unicode_literals
|
||||
|
||||
import functools
|
||||
import re
|
||||
import warnings
|
||||
from importlib import import_module
|
||||
from threading import local
|
||||
|
||||
@ -17,7 +16,6 @@ from django.core.exceptions import ImproperlyConfigured, ViewDoesNotExist
|
||||
from django.http import Http404
|
||||
from django.utils import lru_cache, six
|
||||
from django.utils.datastructures import MultiValueDict
|
||||
from django.utils.deprecation import RemovedInDjango110Warning
|
||||
from django.utils.encoding import force_str, force_text, iri_to_uri
|
||||
from django.utils.functional import cached_property, lazy
|
||||
from django.utils.http import RFC3986_SUBDELIMS, urlquote
|
||||
@ -80,67 +78,50 @@ class NoReverseMatch(Exception):
|
||||
|
||||
|
||||
@lru_cache.lru_cache(maxsize=None)
|
||||
def get_callable(lookup_view, can_fail=False):
|
||||
def get_callable(lookup_view):
|
||||
"""
|
||||
Return a callable corresponding to lookup_view. This function is used
|
||||
by both resolve() and reverse(), so can_fail allows the caller to choose
|
||||
between returning the input as is and raising an exception when the input
|
||||
string can't be interpreted as an import path.
|
||||
Return a callable corresponding to lookup_view.
|
||||
|
||||
If lookup_view is already a callable, return it.
|
||||
If lookup_view is a string import path that can be resolved to a callable,
|
||||
import that callable and return it.
|
||||
If lookup_view is some other kind of string and can_fail is True, the string
|
||||
is returned as is. If can_fail is False, an exception is raised (either
|
||||
ImportError or ViewDoesNotExist).
|
||||
* If lookup_view is already a callable, return it.
|
||||
* If lookup_view is a string import path that can be resolved to a callable,
|
||||
import that callable and return it, otherwise raise an exception
|
||||
(ImportError or ViewDoesNotExist).
|
||||
"""
|
||||
if callable(lookup_view):
|
||||
return lookup_view
|
||||
|
||||
if not isinstance(lookup_view, six.string_types):
|
||||
raise ViewDoesNotExist(
|
||||
"'%s' is not a callable or a dot-notation path" % lookup_view
|
||||
)
|
||||
raise ViewDoesNotExist("'%s' is not a callable or a dot-notation path" % lookup_view)
|
||||
|
||||
mod_name, func_name = get_mod_func(lookup_view)
|
||||
if not func_name: # No '.' in lookup_view
|
||||
if can_fail:
|
||||
return lookup_view
|
||||
else:
|
||||
raise ImportError(
|
||||
"Could not import '%s'. The path must be fully qualified." %
|
||||
lookup_view)
|
||||
raise ImportError("Could not import '%s'. The path must be fully qualified." % lookup_view)
|
||||
|
||||
try:
|
||||
mod = import_module(mod_name)
|
||||
except ImportError:
|
||||
if can_fail:
|
||||
return lookup_view
|
||||
else:
|
||||
parentmod, submod = get_mod_func(mod_name)
|
||||
if submod and not module_has_submodule(import_module(parentmod), submod):
|
||||
raise ViewDoesNotExist(
|
||||
"Could not import '%s'. Parent module %s does not exist." %
|
||||
(lookup_view, mod_name))
|
||||
(lookup_view, mod_name)
|
||||
)
|
||||
else:
|
||||
raise
|
||||
else:
|
||||
try:
|
||||
view_func = getattr(mod, func_name)
|
||||
except AttributeError:
|
||||
if can_fail:
|
||||
return lookup_view
|
||||
else:
|
||||
raise ViewDoesNotExist(
|
||||
"Could not import '%s'. View does not exist in module %s." %
|
||||
(lookup_view, mod_name))
|
||||
(lookup_view, mod_name)
|
||||
)
|
||||
else:
|
||||
if not callable(view_func):
|
||||
# For backwards compatibility this is raised regardless of can_fail
|
||||
raise ViewDoesNotExist(
|
||||
"Could not import '%s.%s'. View is not callable." %
|
||||
(mod_name, func_name))
|
||||
|
||||
(mod_name, func_name)
|
||||
)
|
||||
return view_func
|
||||
|
||||
|
||||
@ -209,14 +190,7 @@ class LocaleRegexProvider(object):
|
||||
class RegexURLPattern(LocaleRegexProvider):
|
||||
def __init__(self, regex, callback, default_args=None, name=None):
|
||||
LocaleRegexProvider.__init__(self, regex)
|
||||
# callback is either a string like 'foo.views.news.stories.story_detail'
|
||||
# which represents the path to a module and a view function name, or a
|
||||
# callable object (view).
|
||||
if callable(callback):
|
||||
self._callback = callback
|
||||
else:
|
||||
self._callback = None
|
||||
self._callback_str = callback
|
||||
self.callback = callback # the view
|
||||
self.default_args = default_args or {}
|
||||
self.name = name
|
||||
|
||||
@ -239,13 +213,19 @@ class RegexURLPattern(LocaleRegexProvider):
|
||||
|
||||
return ResolverMatch(self.callback, args, kwargs, self.name)
|
||||
|
||||
@property
|
||||
def callback(self):
|
||||
if self._callback is not None:
|
||||
return self._callback
|
||||
|
||||
self._callback = get_callable(self._callback_str)
|
||||
return self._callback
|
||||
@cached_property
|
||||
def lookup_str(self):
|
||||
"""
|
||||
A string that identifies the view (e.g. 'path.to.view_function' or
|
||||
'path.to.ClassBasedView').
|
||||
"""
|
||||
callback = self.callback
|
||||
if isinstance(callback, functools.partial):
|
||||
callback = callback.func
|
||||
if not hasattr(callback, '__name__'):
|
||||
return callback.__module__ + "." + callback.__class__.__name__
|
||||
else:
|
||||
return callback.__module__ + "." + callback.__name__
|
||||
|
||||
|
||||
class RegexURLResolver(LocaleRegexProvider):
|
||||
@ -283,18 +263,8 @@ class RegexURLResolver(LocaleRegexProvider):
|
||||
apps = {}
|
||||
language_code = get_language()
|
||||
for pattern in reversed(self.url_patterns):
|
||||
if hasattr(pattern, '_callback_str'):
|
||||
self._callback_strs.add(pattern._callback_str)
|
||||
elif hasattr(pattern, '_callback'):
|
||||
callback = pattern._callback
|
||||
if isinstance(callback, functools.partial):
|
||||
callback = callback.func
|
||||
|
||||
if not hasattr(callback, '__name__'):
|
||||
lookup_str = callback.__module__ + "." + callback.__class__.__name__
|
||||
else:
|
||||
lookup_str = callback.__module__ + "." + callback.__name__
|
||||
self._callback_strs.add(lookup_str)
|
||||
if isinstance(pattern, RegexURLPattern):
|
||||
self._callback_strs.add(pattern.lookup_str)
|
||||
p_pattern = pattern.regex.pattern
|
||||
if p_pattern.startswith('^'):
|
||||
p_pattern = p_pattern[1:]
|
||||
@ -427,9 +397,6 @@ class RegexURLResolver(LocaleRegexProvider):
|
||||
callback = getattr(urls, 'handler%s' % view_type)
|
||||
return get_callable(callback), {}
|
||||
|
||||
def reverse(self, lookup_view, *args, **kwargs):
|
||||
return self._reverse_with_prefix(lookup_view, '', *args, **kwargs)
|
||||
|
||||
def _reverse_with_prefix(self, lookup_view, _prefix, *args, **kwargs):
|
||||
if args and kwargs:
|
||||
raise ValueError("Don't mix *args and **kwargs in call to reverse()!")
|
||||
@ -439,18 +406,6 @@ class RegexURLResolver(LocaleRegexProvider):
|
||||
if not self._populated:
|
||||
self._populate()
|
||||
|
||||
original_lookup = lookup_view
|
||||
try:
|
||||
if self._is_callback(lookup_view):
|
||||
lookup_view = get_callable(lookup_view, True)
|
||||
except (ImportError, AttributeError) as e:
|
||||
raise NoReverseMatch("Error importing '%s': %s." % (lookup_view, e))
|
||||
else:
|
||||
if not callable(original_lookup) and callable(lookup_view):
|
||||
warnings.warn(
|
||||
'Reversing by dotted path is deprecated (%s).' % original_lookup,
|
||||
RemovedInDjango110Warning, stacklevel=3
|
||||
)
|
||||
possibilities = self.reverse_dict.getlist(lookup_view)
|
||||
|
||||
for possibility, pattern, defaults in possibilities:
|
||||
@ -484,9 +439,8 @@ class RegexURLResolver(LocaleRegexProvider):
|
||||
if url.startswith('//'):
|
||||
url = '/%%2F%s' % url[2:]
|
||||
return url
|
||||
# lookup_view can be URL label, or dotted path, or callable, Any of
|
||||
# these can be passed in at the top, but callables are not friendly in
|
||||
# error messages.
|
||||
# lookup_view can be URL name or callable, but callables are not
|
||||
# friendly in error messages.
|
||||
m = getattr(lookup_view, '__module__', None)
|
||||
n = getattr(lookup_view, '__name__', None)
|
||||
if m is not None and n is not None:
|
||||
|
@ -1051,13 +1051,6 @@ This will follow the normal :ref:`namespaced URL resolution strategy
|
||||
<topics-http-reversing-url-namespaces>`, including using any hints provided
|
||||
by the context as to the current application.
|
||||
|
||||
.. deprecated:: 1.8
|
||||
|
||||
You can also pass a dotted Python path to a view function, but this syntax
|
||||
is deprecated and will be removed in Django 1.10::
|
||||
|
||||
{% url 'path.to.some_view' v1 v2 %}
|
||||
|
||||
.. warning::
|
||||
|
||||
Don't forget to put quotes around the :func:`~django.conf.urls.url`
|
||||
|
@ -12,9 +12,8 @@ your code, Django provides the following function:
|
||||
|
||||
.. function:: reverse(viewname, urlconf=None, args=None, kwargs=None, current_app=None)
|
||||
|
||||
``viewname`` can be a string containing the Python path to the view object, a
|
||||
:ref:`URL pattern name <naming-url-patterns>`, or the callable view object.
|
||||
For example, given the following ``url``::
|
||||
``viewname`` can be a :ref:`URL pattern name <naming-url-patterns>` or the
|
||||
callable view object. For example, given the following ``url``::
|
||||
|
||||
from news import views
|
||||
|
||||
@ -63,24 +62,6 @@ namespaces into URLs on specific application instances, according to the
|
||||
The ``urlconf`` argument is the URLconf module containing the url patterns to
|
||||
use for reversing. By default, the root URLconf for the current thread is used.
|
||||
|
||||
.. deprecated:: 1.8
|
||||
|
||||
The ability to reverse using the Python path, e.g.
|
||||
``reverse('news.views.archive')``, has been deprecated.
|
||||
|
||||
.. admonition:: Make sure your views are all correct.
|
||||
|
||||
As part of working out which URL names map to which patterns, the
|
||||
``reverse()`` function has to import all of your URLconf files and examine
|
||||
the name of each view. This involves importing each view function. If
|
||||
there are *any* errors whilst importing any of your view functions, it
|
||||
will cause ``reverse()`` to raise an error, even if that view function is
|
||||
not the one you are trying to reverse.
|
||||
|
||||
Make sure that any views you reference in your URLconf files exist and can
|
||||
be imported correctly. Do not include lines that reference views you
|
||||
haven't written yet, because those views will not be importable.
|
||||
|
||||
.. note::
|
||||
|
||||
The string returned by ``reverse()`` is already
|
||||
|
@ -7,10 +7,8 @@ from xml.dom import minidom
|
||||
from django.conf import settings
|
||||
from django.contrib.sites.models import Site
|
||||
from django.test import (
|
||||
TestCase, ignore_warnings, modify_settings, override_settings,
|
||||
skipUnlessDBFeature,
|
||||
TestCase, modify_settings, override_settings, skipUnlessDBFeature,
|
||||
)
|
||||
from django.utils.deprecation import RemovedInDjango110Warning
|
||||
|
||||
from .models import City, Country
|
||||
|
||||
@ -30,17 +28,9 @@ class GeoSitemapTest(TestCase):
|
||||
expected = set(expected)
|
||||
self.assertEqual(actual, expected)
|
||||
|
||||
@ignore_warnings(category=RemovedInDjango110Warning)
|
||||
def test_geositemap_kml(self):
|
||||
"Tests KML/KMZ geographic sitemaps."
|
||||
for kml_type in ('kml', 'kmz'):
|
||||
# The URL for the sitemaps in urls.py have been updated
|
||||
# with a name but since reversing by Python path is tried first
|
||||
# before reversing by name and works since we're giving
|
||||
# name='django.contrib.gis.sitemaps.views.(kml|kmz)', we need
|
||||
# to silence the erroneous warning until reversing by dotted
|
||||
# path is removed. The test will work without modification when
|
||||
# it's removed.
|
||||
doc = minidom.parseString(self.client.get('/sitemaps/%s.xml' % kml_type).content)
|
||||
|
||||
# Ensuring the right sitemaps namespace is present.
|
||||
|
@ -3,9 +3,8 @@ from __future__ import unicode_literals
|
||||
from django.contrib.auth.views import logout
|
||||
from django.core.urlresolvers import NoReverseMatch, reverse_lazy
|
||||
from django.shortcuts import resolve_url
|
||||
from django.test import SimpleTestCase, ignore_warnings, override_settings
|
||||
from django.test import SimpleTestCase, override_settings
|
||||
from django.utils import six
|
||||
from django.utils.deprecation import RemovedInDjango110Warning
|
||||
|
||||
from .models import UnimportantThing
|
||||
|
||||
@ -51,8 +50,8 @@ class ResolveUrlTests(SimpleTestCase):
|
||||
|
||||
def test_view_function(self):
|
||||
"""
|
||||
Tests that passing a view name to ``resolve_url`` will result in the
|
||||
URL path mapping to that view name.
|
||||
Tests that passing a view function to ``resolve_url`` will result in
|
||||
the URL path mapping to that view name.
|
||||
"""
|
||||
resolved_url = resolve_url(logout)
|
||||
self.assertEqual('/accounts/logout/', resolved_url)
|
||||
@ -66,13 +65,12 @@ class ResolveUrlTests(SimpleTestCase):
|
||||
self.assertIsInstance(resolved_url, six.text_type)
|
||||
self.assertEqual('/accounts/logout/', resolved_url)
|
||||
|
||||
@ignore_warnings(category=RemovedInDjango110Warning)
|
||||
def test_valid_view_name(self):
|
||||
"""
|
||||
Tests that passing a view function to ``resolve_url`` will result in
|
||||
the URL path mapping to that view.
|
||||
Tests that passing a view name to ``resolve_url`` will result in the
|
||||
URL path mapping to that view.
|
||||
"""
|
||||
resolved_url = resolve_url('django.contrib.auth.views.logout')
|
||||
resolved_url = resolve_url('logout')
|
||||
self.assertEqual('/accounts/logout/', resolved_url)
|
||||
|
||||
def test_domain(self):
|
||||
|
@ -9,9 +9,8 @@ from django.conf import settings
|
||||
from django.contrib.sitemaps import GenericSitemap, Sitemap
|
||||
from django.contrib.sites.models import Site
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
from django.test import ignore_warnings, modify_settings, override_settings
|
||||
from django.test import modify_settings, override_settings
|
||||
from django.utils._os import upath
|
||||
from django.utils.deprecation import RemovedInDjango110Warning
|
||||
from django.utils.formats import localize
|
||||
from django.utils.translation import activate, deactivate
|
||||
|
||||
@ -21,15 +20,8 @@ from .models import TestModel
|
||||
|
||||
class HTTPSitemapTests(SitemapTestsBase):
|
||||
|
||||
@ignore_warnings(category=RemovedInDjango110Warning)
|
||||
def test_simple_sitemap_index(self):
|
||||
"A simple sitemap index can be rendered"
|
||||
# The URL for views.sitemap in tests/urls/http.py has been updated
|
||||
# with a name but since reversing by Python path is tried first
|
||||
# before reversing by name and works since we're giving
|
||||
# name='django.contrib.sitemaps.views.sitemap', we need to silence
|
||||
# the erroneous warning until reversing by dotted path is removed.
|
||||
# The test will work without modification when it's removed.
|
||||
response = self.client.get('/simple/index.xml')
|
||||
expected_content = """<?xml version="1.0" encoding="UTF-8"?>
|
||||
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||
@ -38,19 +30,12 @@ class HTTPSitemapTests(SitemapTestsBase):
|
||||
""" % self.base_url
|
||||
self.assertXMLEqual(response.content.decode('utf-8'), expected_content)
|
||||
|
||||
@ignore_warnings(category=RemovedInDjango110Warning)
|
||||
@override_settings(TEMPLATES=[{
|
||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
||||
'DIRS': [os.path.join(os.path.dirname(upath(__file__)), 'templates')],
|
||||
}])
|
||||
def test_simple_sitemap_custom_index(self):
|
||||
"A simple sitemap index can be rendered with a custom template"
|
||||
# The URL for views.sitemap in tests/urls/http.py has been updated
|
||||
# with a name but since reversing by Python path is tried first
|
||||
# before reversing by name and works since we're giving
|
||||
# name='django.contrib.sitemaps.views.sitemap', we need to silence
|
||||
# the erroneous warning until reversing by dotted path is removed.
|
||||
# The test will work without modification when it's removed.
|
||||
response = self.client.get('/simple/custom-index.xml')
|
||||
expected_content = """<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- This is a customised template -->
|
||||
@ -194,14 +179,7 @@ class HTTPSitemapTests(SitemapTestsBase):
|
||||
""" % self.base_url
|
||||
self.assertXMLEqual(response.content.decode('utf-8'), expected_content)
|
||||
|
||||
@ignore_warnings(category=RemovedInDjango110Warning)
|
||||
def test_x_robots_sitemap(self):
|
||||
# The URL for views.sitemap in tests/urls/http.py has been updated
|
||||
# with a name but since reversing by Python path is tried first
|
||||
# before reversing by name and works since we're giving
|
||||
# name='django.contrib.sitemaps.views.sitemap', we need to silence
|
||||
# the erroneous warning until reversing by dotted path is removed.
|
||||
# The test will work without modification when it's removed.
|
||||
response = self.client.get('/simple/index.xml')
|
||||
self.assertEqual(response['X-Robots-Tag'], 'noindex, noodp, noarchive')
|
||||
|
||||
|
@ -2,8 +2,7 @@ from __future__ import unicode_literals
|
||||
|
||||
from datetime import date
|
||||
|
||||
from django.test import ignore_warnings, override_settings
|
||||
from django.utils.deprecation import RemovedInDjango110Warning
|
||||
from django.test import override_settings
|
||||
|
||||
from .base import SitemapTestsBase
|
||||
|
||||
@ -12,15 +11,8 @@ from .base import SitemapTestsBase
|
||||
class HTTPSSitemapTests(SitemapTestsBase):
|
||||
protocol = 'https'
|
||||
|
||||
@ignore_warnings(category=RemovedInDjango110Warning)
|
||||
def test_secure_sitemap_index(self):
|
||||
"A secure sitemap index can be rendered"
|
||||
# The URL for views.sitemap in tests/urls/https.py has been updated
|
||||
# with a name but since reversing by Python path is tried first
|
||||
# before reversing by name and works since we're giving
|
||||
# name='django.contrib.sitemaps.views.sitemap', we need to silence
|
||||
# the erroneous warning until reversing by dotted path is removed.
|
||||
# The test will work without modification when it's removed.
|
||||
response = self.client.get('/secure/index.xml')
|
||||
expected_content = """<?xml version="1.0" encoding="UTF-8"?>
|
||||
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||
@ -44,15 +36,8 @@ class HTTPSSitemapTests(SitemapTestsBase):
|
||||
class HTTPSDetectionSitemapTests(SitemapTestsBase):
|
||||
extra = {'wsgi.url_scheme': 'https'}
|
||||
|
||||
@ignore_warnings(category=RemovedInDjango110Warning)
|
||||
def test_sitemap_index_with_https_request(self):
|
||||
"A sitemap index requested in HTTPS is rendered with HTTPS links"
|
||||
# The URL for views.sitemap in tests/urls/https.py has been updated
|
||||
# with a name but since reversing by Python path is tried first
|
||||
# before reversing by name and works since we're giving
|
||||
# name='django.contrib.sitemaps.views.sitemap', we need to silence
|
||||
# the erroneous warning until reversing by dotted path is removed.
|
||||
# The test will work without modification when it's removed.
|
||||
response = self.client.get('/simple/index.xml', **self.extra)
|
||||
expected_content = """<?xml version="1.0" encoding="UTF-8"?>
|
||||
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||
|
@ -1,10 +1,7 @@
|
||||
# coding: utf-8
|
||||
from django.core.urlresolvers import NoReverseMatch, resolve
|
||||
from django.template import RequestContext, TemplateSyntaxError
|
||||
from django.test import (
|
||||
RequestFactory, SimpleTestCase, ignore_warnings, override_settings,
|
||||
)
|
||||
from django.utils.deprecation import RemovedInDjango110Warning
|
||||
from django.test import RequestFactory, SimpleTestCase, override_settings
|
||||
|
||||
from ..utils import setup
|
||||
|
||||
@ -13,38 +10,32 @@ from ..utils import setup
|
||||
class UrlTagTests(SimpleTestCase):
|
||||
|
||||
# Successes
|
||||
@ignore_warnings(category=RemovedInDjango110Warning)
|
||||
@setup({'url01': '{% url "template_tests.views.client" client.id %}'})
|
||||
@setup({'url01': '{% url "client" client.id %}'})
|
||||
def test_url01(self):
|
||||
output = self.engine.render_to_string('url01', {'client': {'id': 1}})
|
||||
self.assertEqual(output, '/client/1/')
|
||||
|
||||
@ignore_warnings(category=RemovedInDjango110Warning)
|
||||
@setup({'url02': '{% url "template_tests.views.client_action" id=client.id action="update" %}'})
|
||||
@setup({'url02': '{% url "client_action" id=client.id action="update" %}'})
|
||||
def test_url02(self):
|
||||
output = self.engine.render_to_string('url02', {'client': {'id': 1}})
|
||||
self.assertEqual(output, '/client/1/update/')
|
||||
|
||||
@ignore_warnings(category=RemovedInDjango110Warning)
|
||||
@setup({'url02a': '{% url "template_tests.views.client_action" client.id "update" %}'})
|
||||
@setup({'url02a': '{% url "client_action" client.id "update" %}'})
|
||||
def test_url02a(self):
|
||||
output = self.engine.render_to_string('url02a', {'client': {'id': 1}})
|
||||
self.assertEqual(output, '/client/1/update/')
|
||||
|
||||
@ignore_warnings(category=RemovedInDjango110Warning)
|
||||
@setup({'url02b': "{% url 'template_tests.views.client_action' id=client.id action='update' %}"})
|
||||
@setup({'url02b': "{% url 'client_action' id=client.id action='update' %}"})
|
||||
def test_url02b(self):
|
||||
output = self.engine.render_to_string('url02b', {'client': {'id': 1}})
|
||||
self.assertEqual(output, '/client/1/update/')
|
||||
|
||||
@ignore_warnings(category=RemovedInDjango110Warning)
|
||||
@setup({'url02c': "{% url 'template_tests.views.client_action' client.id 'update' %}"})
|
||||
@setup({'url02c': "{% url 'client_action' client.id 'update' %}"})
|
||||
def test_url02c(self):
|
||||
output = self.engine.render_to_string('url02c', {'client': {'id': 1}})
|
||||
self.assertEqual(output, '/client/1/update/')
|
||||
|
||||
@ignore_warnings(category=RemovedInDjango110Warning)
|
||||
@setup({'url03': '{% url "template_tests.views.index" %}'})
|
||||
@setup({'url03': '{% url "index" %}'})
|
||||
def test_url03(self):
|
||||
output = self.engine.render_to_string('url03')
|
||||
self.assertEqual(output, '/')
|
||||
@ -64,12 +55,6 @@ class UrlTagTests(SimpleTestCase):
|
||||
output = self.engine.render_to_string('url06', {'v': 'Ω'})
|
||||
self.assertEqual(output, '/%D0%AE%D0%BD%D0%B8%D0%BA%D0%BE%D0%B4/%CE%A9/')
|
||||
|
||||
@ignore_warnings(category=RemovedInDjango110Warning)
|
||||
@setup({'url07': '{% url "template_tests.views.client2" tag=v %}'})
|
||||
def test_url07(self):
|
||||
output = self.engine.render_to_string('url07', {'v': 'Ω'})
|
||||
self.assertEqual(output, '/%D0%AE%D0%BD%D0%B8%D0%BA%D0%BE%D0%B4/%CE%A9/')
|
||||
|
||||
@setup({'url08': '{% url "метка_оператора" v %}'})
|
||||
def test_url08(self):
|
||||
output = self.engine.render_to_string('url08', {'v': 'Ω'})
|
||||
@ -80,55 +65,45 @@ class UrlTagTests(SimpleTestCase):
|
||||
output = self.engine.render_to_string('url09', {'v': 'Ω'})
|
||||
self.assertEqual(output, '/%D0%AE%D0%BD%D0%B8%D0%BA%D0%BE%D0%B4/%CE%A9/')
|
||||
|
||||
@ignore_warnings(category=RemovedInDjango110Warning)
|
||||
@setup({'url10': '{% url "template_tests.views.client_action" id=client.id action="two words" %}'})
|
||||
@setup({'url10': '{% url "client_action" id=client.id action="two words" %}'})
|
||||
def test_url10(self):
|
||||
output = self.engine.render_to_string('url10', {'client': {'id': 1}})
|
||||
self.assertEqual(output, '/client/1/two%20words/')
|
||||
|
||||
@ignore_warnings(category=RemovedInDjango110Warning)
|
||||
@setup({'url11': '{% url "template_tests.views.client_action" id=client.id action="==" %}'})
|
||||
@setup({'url11': '{% url "client_action" id=client.id action="==" %}'})
|
||||
def test_url11(self):
|
||||
output = self.engine.render_to_string('url11', {'client': {'id': 1}})
|
||||
self.assertEqual(output, '/client/1/==/')
|
||||
|
||||
@setup({'url12': '{% url "template_tests.views.client_action" '
|
||||
'id=client.id action="!$&\'()*+,;=~:@," %}'})
|
||||
@ignore_warnings(category=RemovedInDjango110Warning)
|
||||
@setup({'url12': '{% url "client_action" id=client.id action="!$&\'()*+,;=~:@," %}'})
|
||||
def test_url12(self):
|
||||
output = self.engine.render_to_string('url12', {'client': {'id': 1}})
|
||||
self.assertEqual(output, '/client/1/!$&'()*+,;=~:@,/')
|
||||
|
||||
@ignore_warnings(category=RemovedInDjango110Warning)
|
||||
@setup({'url13': '{% url "template_tests.views.client_action" '
|
||||
'id=client.id action=arg|join:"-" %}'})
|
||||
@setup({'url13': '{% url "client_action" id=client.id action=arg|join:"-" %}'})
|
||||
def test_url13(self):
|
||||
output = self.engine.render_to_string('url13', {'client': {'id': 1}, 'arg': ['a', 'b']})
|
||||
self.assertEqual(output, '/client/1/a-b/')
|
||||
|
||||
@ignore_warnings(category=RemovedInDjango110Warning)
|
||||
@setup({'url14': '{% url "template_tests.views.client_action" client.id arg|join:"-" %}'})
|
||||
@setup({'url14': '{% url "client_action" client.id arg|join:"-" %}'})
|
||||
def test_url14(self):
|
||||
output = self.engine.render_to_string('url14', {'client': {'id': 1}, 'arg': ['a', 'b']})
|
||||
self.assertEqual(output, '/client/1/a-b/')
|
||||
|
||||
@ignore_warnings(category=RemovedInDjango110Warning)
|
||||
@setup({'url15': '{% url "template_tests.views.client_action" 12 "test" %}'})
|
||||
@setup({'url15': '{% url "client_action" 12 "test" %}'})
|
||||
def test_url15(self):
|
||||
output = self.engine.render_to_string('url15')
|
||||
self.assertEqual(output, '/client/12/test/')
|
||||
|
||||
@ignore_warnings(category=RemovedInDjango110Warning)
|
||||
@setup({'url18': '{% url "template_tests.views.client" "1,2" %}'})
|
||||
@setup({'url18': '{% url "client" "1,2" %}'})
|
||||
def test_url18(self):
|
||||
output = self.engine.render_to_string('url18')
|
||||
self.assertEqual(output, '/client/1,2/')
|
||||
|
||||
@ignore_warnings(category=RemovedInDjango110Warning)
|
||||
@setup({'url19': '{% url named_url client.id %}'})
|
||||
def test_url19(self):
|
||||
output = self.engine.render_to_string(
|
||||
'url19', {'client': {'id': 1}, 'named_url': 'template_tests.views.client'}
|
||||
'url19', {'client': {'id': 1}, 'named_url': 'client'}
|
||||
)
|
||||
self.assertEqual(output, '/client/1/')
|
||||
|
||||
@ -138,10 +113,8 @@ class UrlTagTests(SimpleTestCase):
|
||||
self.assertEqual(output, '/named-client/1/')
|
||||
|
||||
@setup({'url21': '{% autoescape off %}'
|
||||
'{% url "template_tests.views.client_action" '
|
||||
'id=client.id action="!$&\'()*+,;=~:@," %}'
|
||||
'{% url "client_action" id=client.id action="!$&\'()*+,;=~:@," %}'
|
||||
'{% endautoescape %}'})
|
||||
@ignore_warnings(category=RemovedInDjango110Warning)
|
||||
def test_url21(self):
|
||||
output = self.engine.render_to_string('url21', {'client': {'id': 1}})
|
||||
self.assertEqual(output, '/client/1/!$&\'()*+,;=~:@,/')
|
||||
@ -157,8 +130,7 @@ class UrlTagTests(SimpleTestCase):
|
||||
with self.assertRaises(NoReverseMatch):
|
||||
self.engine.render_to_string('url-fail02')
|
||||
|
||||
@ignore_warnings(category=RemovedInDjango110Warning)
|
||||
@setup({'url-fail03': '{% url "template_tests.views.client" %}'})
|
||||
@setup({'url-fail03': '{% url "client" %}'})
|
||||
def test_url_fail03(self):
|
||||
with self.assertRaises(NoReverseMatch):
|
||||
self.engine.render_to_string('url-fail03')
|
||||
@ -203,7 +175,6 @@ class UrlTagTests(SimpleTestCase):
|
||||
with self.assertRaises(NoReverseMatch):
|
||||
self.engine.render_to_string('url-fail12', {'named_url': 'no_such_view'})
|
||||
|
||||
@ignore_warnings(category=RemovedInDjango110Warning)
|
||||
@setup({'url-fail13': '{% url named_url %}'})
|
||||
def test_url_fail13(self):
|
||||
with self.assertRaises(NoReverseMatch):
|
||||
@ -240,14 +211,12 @@ class UrlTagTests(SimpleTestCase):
|
||||
self.engine.render_to_string('url-fail19', {'named_url': 'view'})
|
||||
|
||||
# {% url ... as var %}
|
||||
@ignore_warnings(category=RemovedInDjango110Warning)
|
||||
@setup({'url-asvar01': '{% url "template_tests.views.index" as url %}'})
|
||||
@setup({'url-asvar01': '{% url "index" as url %}'})
|
||||
def test_url_asvar01(self):
|
||||
output = self.engine.render_to_string('url-asvar01')
|
||||
self.assertEqual(output, '')
|
||||
|
||||
@ignore_warnings(category=RemovedInDjango110Warning)
|
||||
@setup({'url-asvar02': '{% url "template_tests.views.index" as url %}{{ url }}'})
|
||||
@setup({'url-asvar02': '{% url "index" as url %}{{ url }}'})
|
||||
def test_url_asvar02(self):
|
||||
output = self.engine.render_to_string('url-asvar02')
|
||||
self.assertEqual(output, '/')
|
||||
|
@ -7,10 +7,10 @@ from . import views
|
||||
|
||||
ns_patterns = [
|
||||
# Test urls for testing reverse lookups
|
||||
url(r'^$', views.index),
|
||||
url(r'^client/([0-9,]+)/$', views.client),
|
||||
url(r'^client/(?P<id>[0-9]+)/(?P<action>[^/]+)/$', views.client_action),
|
||||
url(r'^client/(?P<client_id>[0-9]+)/(?P<action>[^/]+)/$', views.client_action),
|
||||
url(r'^$', views.index, name='index'),
|
||||
url(r'^client/([0-9,]+)/$', views.client, name='client'),
|
||||
url(r'^client/(?P<id>[0-9]+)/(?P<action>[^/]+)/$', views.client_action, name='client_action'),
|
||||
url(r'^client/(?P<client_id>[0-9]+)/(?P<action>[^/]+)/$', views.client_action, name='client_action'),
|
||||
url(r'^named-client/([0-9]+)/$', views.client2, name="named.client"),
|
||||
]
|
||||
|
||||
|
@ -1,30 +1,7 @@
|
||||
import warnings
|
||||
|
||||
from django.conf.urls import url
|
||||
from django.utils.deprecation import RemovedInDjango110Warning
|
||||
|
||||
from . import views
|
||||
|
||||
# Test deprecated behavior of passing strings as view to url().
|
||||
# Some of these can be removed in Django 1.10 as they aren't convertable to
|
||||
# callables.
|
||||
with warnings.catch_warnings():
|
||||
warnings.filterwarnings('ignore', category=RemovedInDjango110Warning)
|
||||
urlpatterns = [
|
||||
# View has erroneous import
|
||||
url(r'erroneous_inner/$', views.erroneous_view),
|
||||
# Module has erroneous import
|
||||
url(r'erroneous_outer/$', 'urlpatterns_reverse.erroneous_views_module.erroneous_view'),
|
||||
# Module is an unqualified string
|
||||
url(r'erroneous_unqualified/$', 'unqualified_view'),
|
||||
# View does not exist
|
||||
url(r'missing_inner/$', 'urlpatterns_reverse.views.missing_view'),
|
||||
# View is not a callable (string import; arbitrary Python object)
|
||||
url(r'uncallable-dotted/$', 'urlpatterns_reverse.views.uncallable'),
|
||||
# View is not a callable (explicit import; arbitrary Python object)
|
||||
url(r'uncallable-object/$', views.uncallable),
|
||||
# Module does not exist
|
||||
url(r'missing_outer/$', 'urlpatterns_reverse.missing_module.missing_view'),
|
||||
# Regex contains an error (refs #6170)
|
||||
urlpatterns = [
|
||||
url(r'(regex_error/$', views.empty_view),
|
||||
]
|
||||
]
|
||||
|
@ -1,5 +0,0 @@
|
||||
import non_existent # NOQA
|
||||
|
||||
|
||||
def erroneous_view(request):
|
||||
pass
|
@ -26,9 +26,7 @@ from django.test import (
|
||||
)
|
||||
from django.test.utils import override_script_prefix
|
||||
from django.utils import six
|
||||
from django.utils.deprecation import (
|
||||
RemovedInDjango20Warning, RemovedInDjango110Warning,
|
||||
)
|
||||
from django.utils.deprecation import RemovedInDjango20Warning
|
||||
|
||||
from . import middleware, urlconf_outer, views
|
||||
from .views import empty_view
|
||||
@ -231,13 +229,6 @@ test_data = (
|
||||
('nested-namedcapture', NoReverseMatch, [], {'outer': 'opt/', 'inner': 'opt'}),
|
||||
('nested-namedcapture', NoReverseMatch, [], {'inner': 'opt'}),
|
||||
|
||||
# Regression for #9038
|
||||
# These views are resolved by method name. Each method is deployed twice -
|
||||
# once with an explicit argument, and once using the default value on
|
||||
# the method. This is potentially ambiguous, as you have to pick the
|
||||
# correct view for the arguments provided.
|
||||
('urlpatterns_reverse.views.absolute_kwargs_view', '/absolute_arg_view/', [], {}),
|
||||
('urlpatterns_reverse.views.absolute_kwargs_view', '/absolute_arg_view/10/', [], {'arg1': 10}),
|
||||
('non_path_include', '/includes/non_path_include/', [], {}),
|
||||
|
||||
# Tests for #13154
|
||||
@ -292,7 +283,6 @@ class NoURLPatternsTests(SimpleTestCase):
|
||||
@override_settings(ROOT_URLCONF='urlpatterns_reverse.urls')
|
||||
class URLPatternReverse(SimpleTestCase):
|
||||
|
||||
@ignore_warnings(category=RemovedInDjango110Warning)
|
||||
def test_urlpattern_reverse(self):
|
||||
for name, expected, args, kwargs in test_data:
|
||||
try:
|
||||
@ -544,11 +534,10 @@ class ReverseShortcutTests(SimpleTestCase):
|
||||
redirect("urlpatterns_reverse.nonimported_module.view")
|
||||
self.assertNotIn("urlpatterns_reverse.nonimported_module", sys.modules)
|
||||
|
||||
@ignore_warnings(category=RemovedInDjango110Warning)
|
||||
def test_reverse_by_path_nested(self):
|
||||
# Views that are added to urlpatterns using include() should be
|
||||
# reversible by dotted path.
|
||||
self.assertEqual(reverse('urlpatterns_reverse.views.nested_view'), '/includes/nested_path/')
|
||||
# Views added to urlpatterns using include() should be reversible.
|
||||
from .views import nested_view
|
||||
self.assertEqual(reverse(nested_view), '/includes/nested_path/')
|
||||
|
||||
def test_redirect_view_object(self):
|
||||
from .views import absolute_kwargs_view
|
||||
@ -982,24 +971,16 @@ class ResolverMatchTests(SimpleTestCase):
|
||||
@override_settings(ROOT_URLCONF='urlpatterns_reverse.erroneous_urls')
|
||||
class ErroneousViewTests(SimpleTestCase):
|
||||
|
||||
def test_erroneous_resolve(self):
|
||||
self.assertRaises(ImportError, self.client.get, '/erroneous_inner/')
|
||||
self.assertRaises(ImportError, self.client.get, '/erroneous_outer/')
|
||||
self.assertRaises(ViewDoesNotExist, self.client.get, '/missing_inner/')
|
||||
self.assertRaises(ViewDoesNotExist, self.client.get, '/missing_outer/')
|
||||
self.assertRaises(ViewDoesNotExist, self.client.get, '/uncallable-dotted/')
|
||||
self.assertRaises(ViewDoesNotExist, self.client.get, '/uncallable-object/')
|
||||
def test_noncallable_view(self):
|
||||
# View is not a callable (explicit import; arbitrary Python object)
|
||||
with self.assertRaisesMessage(TypeError, 'view must be a callable'):
|
||||
url(r'uncallable-object/$', views.uncallable)
|
||||
|
||||
# Regression test for #21157
|
||||
self.assertRaises(ImportError, self.client.get, '/erroneous_unqualified/')
|
||||
|
||||
def test_erroneous_reverse(self):
|
||||
"""
|
||||
Ensure that a useful exception is raised when a regex is invalid in the
|
||||
URLConf (#6170).
|
||||
"""
|
||||
# The regex error will be hit before NoReverseMatch can be raised
|
||||
self.assertRaises(ImproperlyConfigured, reverse, 'whatever blah blah')
|
||||
def test_invalid_regex(self):
|
||||
# Regex contains an error (refs #6170)
|
||||
msg = '(regex_error/$" is not a valid regular expression'
|
||||
with self.assertRaisesMessage(ImproperlyConfigured, msg):
|
||||
reverse(views.empty_view)
|
||||
|
||||
|
||||
class ViewLoadingTests(SimpleTestCase):
|
||||
|
@ -2,7 +2,7 @@ from django.conf.urls import include, url
|
||||
|
||||
from .views import (
|
||||
absolute_kwargs_view, defaults_view, empty_view, empty_view_partial,
|
||||
empty_view_wrapped, kwargs_view, nested_view,
|
||||
empty_view_wrapped, nested_view,
|
||||
)
|
||||
|
||||
other_patterns = [
|
||||
@ -67,10 +67,6 @@ urlpatterns = [
|
||||
# This is non-reversible, but we shouldn't blow up when parsing it.
|
||||
url(r'^(?:foo|bar)(\w+)/$', empty_view, name="disjunction"),
|
||||
|
||||
# Regression views for #9038. See tests for more details
|
||||
url(r'arg_view/$', kwargs_view),
|
||||
url(r'arg_view/(?P<arg1>[0-9]+)/$', kwargs_view),
|
||||
url(r'absolute_arg_view/(?P<arg1>[0-9]+)/$', absolute_kwargs_view),
|
||||
url(r'absolute_arg_view/$', absolute_kwargs_view),
|
||||
|
||||
# Tests for #13154. Mixed syntax to test both ways of defining URLs.
|
||||
|
@ -10,10 +10,6 @@ def empty_view(request, *args, **kwargs):
|
||||
return HttpResponse('')
|
||||
|
||||
|
||||
def kwargs_view(request, arg1=1, arg2=2):
|
||||
return HttpResponse('')
|
||||
|
||||
|
||||
def absolute_kwargs_view(request, arg1=1, arg2=2):
|
||||
return HttpResponse('')
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user