Fixed #26013 -- Moved django.core.urlresolvers to django.urls.

Thanks to Tim Graham for the review.
This commit is contained in:
Marten Kenbeek 2015-12-30 16:51:16 +01:00 committed by Tim Graham
parent df3d5b1d73
commit 16411b8400
117 changed files with 961 additions and 922 deletions

View File

@ -15,7 +15,7 @@ def setup(set_prefix=True):
""" """
from django.apps import apps from django.apps import apps
from django.conf import settings from django.conf import settings
from django.core.urlresolvers import set_script_prefix from django.urls import set_script_prefix
from django.utils.encoding import force_text from django.utils.encoding import force_text
from django.utils.log import configure_logging from django.utils.log import configure_logging

View File

@ -2,7 +2,7 @@ import warnings
from importlib import import_module from importlib import import_module
from django.core.exceptions import ImproperlyConfigured from django.core.exceptions import ImproperlyConfigured
from django.core.urlresolvers import ( from django.urls import (
LocaleRegexURLResolver, RegexURLPattern, RegexURLResolver, LocaleRegexURLResolver, RegexURLPattern, RegexURLResolver,
) )
from django.utils import six from django.utils import six

View File

@ -1,6 +1,6 @@
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.urlresolvers import LocaleRegexURLResolver from django.urls import LocaleRegexURLResolver
from django.views.i18n import set_language from django.views.i18n import set_language

View File

@ -3,8 +3,8 @@ from __future__ import unicode_literals
from django.conf import settings from django.conf import settings
from django.contrib.admin.utils import quote from django.contrib.admin.utils import quote
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.core.urlresolvers import NoReverseMatch, reverse
from django.db import models from django.db import models
from django.urls import NoReverseMatch, reverse
from django.utils import timezone from django.utils import timezone
from django.utils.encoding import python_2_unicode_compatible, smart_text from django.utils.encoding import python_2_unicode_compatible, smart_text
from django.utils.translation import ugettext, ugettext_lazy as _ from django.utils.translation import ugettext, ugettext_lazy as _

View File

@ -24,7 +24,6 @@ from django.core.exceptions import (
FieldDoesNotExist, FieldError, PermissionDenied, ValidationError, FieldDoesNotExist, FieldError, PermissionDenied, ValidationError,
) )
from django.core.paginator import Paginator from django.core.paginator import Paginator
from django.core.urlresolvers import reverse
from django.db import models, router, transaction from django.db import models, router, transaction
from django.db.models.constants import LOOKUP_SEP from django.db.models.constants import LOOKUP_SEP
from django.db.models.fields import BLANK_CHOICE_DASH from django.db.models.fields import BLANK_CHOICE_DASH
@ -37,6 +36,7 @@ from django.forms.widgets import CheckboxSelectMultiple, SelectMultiple
from django.http import Http404, HttpResponseRedirect from django.http import Http404, HttpResponseRedirect
from django.http.response import HttpResponseBase from django.http.response import HttpResponseBase
from django.template.response import SimpleTemplateResponse, TemplateResponse from django.template.response import SimpleTemplateResponse, TemplateResponse
from django.urls import reverse
from django.utils import six from django.utils import six
from django.utils.decorators import method_decorator from django.utils.decorators import method_decorator
from django.utils.encoding import force_text, python_2_unicode_compatible from django.utils.encoding import force_text, python_2_unicode_compatible

View File

@ -5,11 +5,11 @@ from django.conf import settings
from django.contrib.admin import ModelAdmin, actions from django.contrib.admin import ModelAdmin, actions
from django.contrib.auth import REDIRECT_FIELD_NAME from django.contrib.auth import REDIRECT_FIELD_NAME
from django.core.exceptions import ImproperlyConfigured, PermissionDenied from django.core.exceptions import ImproperlyConfigured, PermissionDenied
from django.core.urlresolvers import NoReverseMatch, reverse
from django.db.models.base import ModelBase from django.db.models.base import ModelBase
from django.http import Http404, HttpResponseRedirect from django.http import Http404, HttpResponseRedirect
from django.template.engine import Engine from django.template.engine import Engine
from django.template.response import TemplateResponse from django.template.response import TemplateResponse
from django.urls import NoReverseMatch, reverse
from django.utils import six from django.utils import six
from django.utils.text import capfirst from django.utils.text import capfirst
from django.utils.translation import ugettext as _, ugettext_lazy from django.utils.translation import ugettext as _, ugettext_lazy

View File

@ -11,11 +11,11 @@ from django.contrib.admin.views.main import (
ALL_VAR, ORDER_VAR, PAGE_VAR, SEARCH_VAR, ALL_VAR, ORDER_VAR, PAGE_VAR, SEARCH_VAR,
) )
from django.core.exceptions import ObjectDoesNotExist from django.core.exceptions import ObjectDoesNotExist
from django.core.urlresolvers import NoReverseMatch
from django.db import models from django.db import models
from django.template import Library from django.template import Library
from django.template.loader import get_template from django.template.loader import get_template
from django.templatetags.static import static from django.templatetags.static import static
from django.urls import NoReverseMatch
from django.utils import formats from django.utils import formats
from django.utils.deprecation import RemovedInDjango20Warning from django.utils.deprecation import RemovedInDjango20Warning
from django.utils.encoding import force_text from django.utils.encoding import force_text

View File

@ -1,6 +1,6 @@
from django import template from django import template
from django.contrib.admin.utils import quote from django.contrib.admin.utils import quote
from django.core.urlresolvers import Resolver404, get_script_prefix, resolve from django.urls import Resolver404, get_script_prefix, resolve
from django.utils.http import urlencode from django.utils.http import urlencode
from django.utils.six.moves.urllib.parse import parse_qsl, urlparse, urlunparse from django.utils.six.moves.urllib.parse import parse_qsl, urlparse, urlunparse

View File

@ -6,12 +6,12 @@ from collections import defaultdict
from django.contrib.auth import get_permission_codename from django.contrib.auth import get_permission_codename
from django.core.exceptions import FieldDoesNotExist from django.core.exceptions import FieldDoesNotExist
from django.core.urlresolvers import NoReverseMatch, reverse
from django.db import models from django.db import models
from django.db.models.constants import LOOKUP_SEP from django.db.models.constants import LOOKUP_SEP
from django.db.models.deletion import Collector from django.db.models.deletion import Collector
from django.db.models.sql.constants import QUERY_TERMS from django.db.models.sql.constants import QUERY_TERMS
from django.forms.utils import pretty_name from django.forms.utils import pretty_name
from django.urls import NoReverseMatch, reverse
from django.utils import formats, six, timezone from django.utils import formats, six, timezone
from django.utils.encoding import force_str, force_text, smart_text from django.utils.encoding import force_str, force_text, smart_text
from django.utils.html import format_html from django.utils.html import format_html

View File

@ -15,8 +15,8 @@ from django.core.exceptions import (
FieldDoesNotExist, ImproperlyConfigured, SuspiciousOperation, FieldDoesNotExist, ImproperlyConfigured, SuspiciousOperation,
) )
from django.core.paginator import InvalidPage from django.core.paginator import InvalidPage
from django.core.urlresolvers import reverse
from django.db import models from django.db import models
from django.urls import reverse
from django.utils import six from django.utils import six
from django.utils.encoding import force_text from django.utils.encoding import force_text
from django.utils.http import urlencode from django.utils.http import urlencode

View File

@ -6,11 +6,11 @@ from __future__ import unicode_literals
import copy import copy
from django import forms from django import forms
from django.core.urlresolvers import reverse
from django.db.models.deletion import CASCADE from django.db.models.deletion import CASCADE
from django.forms.utils import flatatt from django.forms.utils import flatatt
from django.forms.widgets import RadioFieldRenderer from django.forms.widgets import RadioFieldRenderer
from django.template.loader import render_to_string from django.template.loader import render_to_string
from django.urls import reverse
from django.utils import six from django.utils import six
from django.utils.encoding import force_text from django.utils.encoding import force_text
from django.utils.html import ( from django.utils.html import (

View File

@ -4,7 +4,7 @@ import re
from email.errors import HeaderParseError from email.errors import HeaderParseError
from email.parser import HeaderParser from email.parser import HeaderParser
from django.core.urlresolvers import reverse from django.urls import reverse
from django.utils.encoding import force_bytes from django.utils.encoding import force_bytes
from django.utils.safestring import mark_safe from django.utils.safestring import mark_safe

View File

@ -8,11 +8,11 @@ from django.conf import settings
from django.contrib import admin from django.contrib import admin
from django.contrib.admin.views.decorators import staff_member_required from django.contrib.admin.views.decorators import staff_member_required
from django.contrib.admindocs import utils from django.contrib.admindocs import utils
from django.core import urlresolvers
from django.core.exceptions import ImproperlyConfigured, ViewDoesNotExist from django.core.exceptions import ImproperlyConfigured, ViewDoesNotExist
from django.db import models from django.db import models
from django.http import Http404 from django.http import Http404
from django.template.engine import Engine from django.template.engine import Engine
from django.urls import get_mod_func, get_resolver, get_urlconf, reverse
from django.utils.decorators import method_decorator from django.utils.decorators import method_decorator
from django.utils.inspect import ( from django.utils.inspect import (
func_accepts_kwargs, func_accepts_var_args, func_has_no_args, func_accepts_kwargs, func_accepts_var_args, func_has_no_args,
@ -38,7 +38,7 @@ class BaseAdminDocsView(TemplateView):
return super(BaseAdminDocsView, self).dispatch(request, *args, **kwargs) return super(BaseAdminDocsView, self).dispatch(request, *args, **kwargs)
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
kwargs.update({'root_path': urlresolvers.reverse('admin:index')}) kwargs.update({'root_path': reverse('admin:index')})
kwargs.update(admin.site.each_context(self.request)) kwargs.update(admin.site.each_context(self.request))
return super(BaseAdminDocsView, self).get_context_data(**kwargs) return super(BaseAdminDocsView, self).get_context_data(**kwargs)
@ -147,9 +147,9 @@ class ViewDetailView(BaseAdminDocsView):
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
view = self.kwargs['view'] view = self.kwargs['view']
urlconf = urlresolvers.get_urlconf() urlconf = get_urlconf()
if urlresolvers.get_resolver(urlconf)._is_callback(view): if get_resolver(urlconf)._is_callback(view):
mod, func = urlresolvers.get_mod_func(view) mod, func = get_mod_func(view)
view_func = getattr(import_module(mod), func) view_func = getattr(import_module(mod), func)
else: else:
raise Http404 raise Http404

View File

@ -9,10 +9,10 @@ from django.contrib.auth.forms import (
) )
from django.contrib.auth.models import Group, User from django.contrib.auth.models import Group, User
from django.core.exceptions import PermissionDenied from django.core.exceptions import PermissionDenied
from django.core.urlresolvers import reverse
from django.db import transaction from django.db import transaction
from django.http import Http404, HttpResponseRedirect from django.http import Http404, HttpResponseRedirect
from django.template.response import TemplateResponse from django.template.response import TemplateResponse
from django.urls import reverse
from django.utils.decorators import method_decorator from django.utils.decorators import method_decorator
from django.utils.encoding import force_text from django.utils.encoding import force_text
from django.utils.html import escape from django.utils.html import escape

View File

@ -13,10 +13,10 @@ from django.contrib.auth.forms import (
) )
from django.contrib.auth.tokens import default_token_generator from django.contrib.auth.tokens import default_token_generator
from django.contrib.sites.shortcuts import get_current_site from django.contrib.sites.shortcuts import get_current_site
from django.core.urlresolvers import reverse
from django.http import HttpResponseRedirect, QueryDict from django.http import HttpResponseRedirect, QueryDict
from django.shortcuts import resolve_url from django.shortcuts import resolve_url
from django.template.response import TemplateResponse from django.template.response import TemplateResponse
from django.urls import reverse
from django.utils.deprecation import RemovedInDjango20Warning from django.utils.deprecation import RemovedInDjango20Warning
from django.utils.encoding import force_text from django.utils.encoding import force_text
from django.utils.http import is_safe_url, urlsafe_base64_decode from django.utils.http import is_safe_url, urlsafe_base64_decode

View File

@ -1,8 +1,8 @@
from __future__ import unicode_literals from __future__ import unicode_literals
from django.contrib.sites.models import Site from django.contrib.sites.models import Site
from django.core.urlresolvers import get_script_prefix
from django.db import models from django.db import models
from django.urls import get_script_prefix
from django.utils.encoding import iri_to_uri, python_2_unicode_compatible from django.utils.encoding import iri_to_uri, python_2_unicode_compatible
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _

View File

@ -1,8 +1,8 @@
from django.apps import apps from django.apps import apps
from django.contrib.gis.db.models.fields import GeometryField from django.contrib.gis.db.models.fields import GeometryField
from django.contrib.sitemaps import Sitemap from django.contrib.sitemaps import Sitemap
from django.core import urlresolvers
from django.db import models from django.db import models
from django.urls import reverse
class KMLSitemap(Sitemap): class KMLSitemap(Sitemap):
@ -56,12 +56,14 @@ class KMLSitemap(Sitemap):
return self.locations return self.locations
def location(self, obj): def location(self, obj):
return urlresolvers.reverse('django.contrib.gis.sitemaps.views.%s' % self.geo_format, return reverse(
kwargs={'label': obj[0], 'django.contrib.gis.sitemaps.views.%s' % self.geo_format,
'model': obj[1], kwargs={
'field_name': obj[2], 'label': obj[0],
} 'model': obj[1],
) 'field_name': obj[2],
},
)
class KMZSitemap(KMLSitemap): class KMZSitemap(KMLSitemap):

View File

@ -1,7 +1,8 @@
from django.apps import apps as django_apps from django.apps import apps as django_apps
from django.conf import settings from django.conf import settings
from django.core import paginator, urlresolvers from django.core import paginator
from django.core.exceptions import ImproperlyConfigured from django.core.exceptions import ImproperlyConfigured
from django.urls import NoReverseMatch, reverse
from django.utils import translation from django.utils import translation
from django.utils.six.moves.urllib.parse import urlencode from django.utils.six.moves.urllib.parse import urlencode
from django.utils.six.moves.urllib.request import urlopen from django.utils.six.moves.urllib.request import urlopen
@ -18,17 +19,17 @@ def ping_google(sitemap_url=None, ping_url=PING_URL):
Alerts Google that the sitemap for the current site has been updated. Alerts Google that the sitemap for the current site has been updated.
If sitemap_url is provided, it should be an absolute path to the sitemap If sitemap_url is provided, it should be an absolute path to the sitemap
for this site -- e.g., '/sitemap.xml'. If sitemap_url is not provided, this for this site -- e.g., '/sitemap.xml'. If sitemap_url is not provided, this
function will attempt to deduce it by using urlresolvers.reverse(). function will attempt to deduce it by using urls.reverse().
""" """
if sitemap_url is None: if sitemap_url is None:
try: try:
# First, try to get the "index" sitemap URL. # First, try to get the "index" sitemap URL.
sitemap_url = urlresolvers.reverse('django.contrib.sitemaps.views.index') sitemap_url = reverse('django.contrib.sitemaps.views.index')
except urlresolvers.NoReverseMatch: except NoReverseMatch:
try: try:
# Next, try for the "global" sitemap URL. # Next, try for the "global" sitemap URL.
sitemap_url = urlresolvers.reverse('django.contrib.sitemaps.views.sitemap') sitemap_url = reverse('django.contrib.sitemaps.views.sitemap')
except urlresolvers.NoReverseMatch: except NoReverseMatch:
pass pass
if sitemap_url is None: if sitemap_url is None:

View File

@ -3,10 +3,10 @@ from calendar import timegm
from functools import wraps from functools import wraps
from django.contrib.sites.shortcuts import get_current_site from django.contrib.sites.shortcuts import get_current_site
from django.core import urlresolvers
from django.core.paginator import EmptyPage, PageNotAnInteger from django.core.paginator import EmptyPage, PageNotAnInteger
from django.http import Http404 from django.http import Http404
from django.template.response import TemplateResponse from django.template.response import TemplateResponse
from django.urls import reverse
from django.utils.http import http_date from django.utils.http import http_date
@ -32,8 +32,7 @@ def index(request, sitemaps,
if callable(site): if callable(site):
site = site() site = site()
protocol = req_protocol if site.protocol is None else site.protocol protocol = req_protocol if site.protocol is None else site.protocol
sitemap_url = urlresolvers.reverse( sitemap_url = reverse(sitemap_url_name, kwargs={'section': section})
sitemap_url_name, kwargs={'section': section})
absolute_url = '%s://%s%s' % (protocol, req_site.domain, sitemap_url) absolute_url = '%s://%s%s' % (protocol, req_site.domain, sitemap_url)
sites.append(absolute_url) sites.append(absolute_url)
for page in range(2, site.paginator.num_pages + 1): for page in range(2, site.paginator.num_pages + 1):

View File

@ -5,7 +5,7 @@ from . import Tags, Warning, register
@register(Tags.urls) @register(Tags.urls)
def check_url_config(app_configs, **kwargs): def check_url_config(app_configs, **kwargs):
from django.core.urlresolvers import get_resolver from django.urls import get_resolver
resolver = get_resolver() resolver = get_resolver()
return check_resolver(resolver) return check_resolver(resolver)
@ -14,7 +14,7 @@ def check_resolver(resolver):
""" """
Recursively check the resolver. Recursively check the resolver.
""" """
from django.core.urlresolvers import RegexURLPattern, RegexURLResolver from django.urls import RegexURLPattern, RegexURLResolver
warnings = [] warnings = []
for pattern in resolver.url_patterns: for pattern in resolver.url_patterns:
if isinstance(pattern, RegexURLResolver): if isinstance(pattern, RegexURLResolver):

View File

@ -7,12 +7,13 @@ import warnings
from django import http from django import http
from django.conf import settings from django.conf import settings
from django.core import signals, urlresolvers from django.core import signals
from django.core.exceptions import ( from django.core.exceptions import (
MiddlewareNotUsed, PermissionDenied, SuspiciousOperation, MiddlewareNotUsed, PermissionDenied, SuspiciousOperation,
) )
from django.db import connections, transaction from django.db import connections, transaction
from django.http.multipartparser import MultiPartParserError from django.http.multipartparser import MultiPartParserError
from django.urls import get_resolver, set_urlconf
from django.utils import six from django.utils import six
from django.utils.deprecation import RemovedInDjango20Warning from django.utils.deprecation import RemovedInDjango20Warning
from django.utils.encoding import force_text from django.utils.encoding import force_text
@ -111,8 +112,8 @@ class BaseHandler(object):
# variable" exception in the event an exception is raised before # variable" exception in the event an exception is raised before
# resolver is set # resolver is set
urlconf = settings.ROOT_URLCONF urlconf = settings.ROOT_URLCONF
urlresolvers.set_urlconf(urlconf) set_urlconf(urlconf)
resolver = urlresolvers.get_resolver(urlconf) resolver = get_resolver(urlconf)
# Use a flag to check if the response was rendered to prevent # Use a flag to check if the response was rendered to prevent
# multiple renderings or to force rendering if necessary. # multiple renderings or to force rendering if necessary.
response_is_rendered = False response_is_rendered = False
@ -128,8 +129,8 @@ class BaseHandler(object):
if hasattr(request, 'urlconf'): if hasattr(request, 'urlconf'):
# Reset url resolver with a custom URLconf. # Reset url resolver with a custom URLconf.
urlconf = request.urlconf urlconf = request.urlconf
urlresolvers.set_urlconf(urlconf) set_urlconf(urlconf)
resolver = urlresolvers.get_resolver(urlconf) resolver = get_resolver(urlconf)
resolver_match = resolver.resolve(request.path_info) resolver_match = resolver.resolve(request.path_info)
callback, callback_args, callback_kwargs = resolver_match callback, callback_args, callback_kwargs = resolver_match

View File

@ -12,7 +12,7 @@ from django import http
from django.conf import settings from django.conf import settings
from django.core import signals from django.core import signals
from django.core.handlers import base from django.core.handlers import base
from django.core.urlresolvers import set_script_prefix from django.urls import set_script_prefix
from django.utils import six from django.utils import six
from django.utils.encoding import force_str, force_text from django.utils.encoding import force_str, force_text
from django.utils.functional import cached_property from django.utils.functional import cached_property

View File

@ -1,640 +1,9 @@
""" import warnings
This module converts requested URLs to callback view functions.
RegexURLResolver is the main class here. Its resolve() method takes a URL (as from django.urls import * # NOQA
a string) and returns a ResolverMatch object which provides access to all from django.utils.deprecation import RemovedInDjango20Warning
attributes of the resolved URL match.
"""
from __future__ import unicode_literals
import functools warnings.warn(
import re "Importing from django.core.urlresolvers is deprecated in favor of "
from importlib import import_module "django.urls.", RemovedInDjango20Warning, stacklevel=2
from threading import local )
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.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
from django.utils.module_loading import module_has_submodule
from django.utils.regex_helper import normalize
from django.utils.six.moves.urllib.parse import urlsplit, urlunsplit
from django.utils.translation import get_language, override
# SCRIPT_NAME prefixes for each thread are stored here. If there's no entry for
# the current thread (which is the only one we ever access), it is assumed to
# be empty.
_prefixes = local()
# Overridden URLconfs for each thread are stored here.
_urlconfs = local()
class ResolverMatch(object):
def __init__(self, func, args, kwargs, url_name=None, app_names=None, namespaces=None):
self.func = func
self.args = args
self.kwargs = kwargs
self.url_name = url_name
# If a URLRegexResolver doesn't have a namespace or app_name, it passes
# in an empty value.
self.app_names = [x for x in app_names if x] if app_names else []
self.app_name = ':'.join(self.app_names)
if namespaces:
self.namespaces = [x for x in namespaces if x]
else:
self.namespaces = []
self.namespace = ':'.join(self.namespaces)
if not hasattr(func, '__name__'):
# A class-based view
self._func_path = '.'.join([func.__class__.__module__, func.__class__.__name__])
else:
# A function-based view
self._func_path = '.'.join([func.__module__, func.__name__])
view_path = url_name or self._func_path
self.view_name = ':'.join(self.namespaces + [view_path])
def __getitem__(self, index):
return (self.func, self.args, self.kwargs)[index]
def __repr__(self):
return "ResolverMatch(func=%s, args=%s, kwargs=%s, url_name=%s, app_names=%s, namespaces=%s)" % (
self._func_path, self.args, self.kwargs, self.url_name, self.app_names, self.namespaces)
class Resolver404(Http404):
pass
class NoReverseMatch(Exception):
pass
@lru_cache.lru_cache(maxsize=None)
def get_callable(lookup_view):
"""
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, 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)
mod_name, func_name = get_mod_func(lookup_view)
if not func_name: # No '.' in lookup_view
raise ImportError("Could not import '%s'. The path must be fully qualified." % lookup_view)
try:
mod = import_module(mod_name)
except ImportError:
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)
)
else:
raise
else:
try:
view_func = getattr(mod, func_name)
except AttributeError:
raise ViewDoesNotExist(
"Could not import '%s'. View does not exist in module %s." %
(lookup_view, mod_name)
)
else:
if not callable(view_func):
raise ViewDoesNotExist(
"Could not import '%s.%s'. View is not callable." %
(mod_name, func_name)
)
return view_func
@lru_cache.lru_cache(maxsize=None)
def get_resolver(urlconf=None):
if urlconf is None:
from django.conf import settings
urlconf = settings.ROOT_URLCONF
return RegexURLResolver(r'^/', urlconf)
@lru_cache.lru_cache(maxsize=None)
def get_ns_resolver(ns_pattern, resolver):
# Build a namespaced resolver for the given parent URLconf pattern.
# This makes it possible to have captured parameters in the parent
# URLconf pattern.
ns_resolver = RegexURLResolver(ns_pattern, resolver.url_patterns)
return RegexURLResolver(r'^/', [ns_resolver])
def get_mod_func(callback):
# Converts 'django.views.news.stories.story_detail' to
# ['django.views.news.stories', 'story_detail']
try:
dot = callback.rindex('.')
except ValueError:
return callback, ''
return callback[:dot], callback[dot + 1:]
class LocaleRegexProvider(object):
"""
A mixin to provide a default regex property which can vary by active
language.
"""
def __init__(self, regex):
# regex is either a string representing a regular expression, or a
# translatable string (using ugettext_lazy) representing a regular
# expression.
self._regex = regex
self._regex_dict = {}
@property
def regex(self):
"""
Returns a compiled regular expression, depending upon the activated
language-code.
"""
language_code = get_language()
if language_code not in self._regex_dict:
if isinstance(self._regex, six.string_types):
regex = self._regex
else:
regex = force_text(self._regex)
try:
compiled_regex = re.compile(regex, re.UNICODE)
except re.error as e:
raise ImproperlyConfigured(
'"%s" is not a valid regular expression: %s' %
(regex, six.text_type(e)))
self._regex_dict[language_code] = compiled_regex
return self._regex_dict[language_code]
class RegexURLPattern(LocaleRegexProvider):
def __init__(self, regex, callback, default_args=None, name=None):
LocaleRegexProvider.__init__(self, regex)
self.callback = callback # the view
self.default_args = default_args or {}
self.name = name
def __repr__(self):
return force_str('<%s %s %s>' % (self.__class__.__name__, self.name, self.regex.pattern))
def resolve(self, path):
match = self.regex.search(path)
if match:
# If there are any named groups, use those as kwargs, ignoring
# non-named groups. Otherwise, pass all non-named arguments as
# positional arguments.
kwargs = match.groupdict()
if kwargs:
args = ()
else:
args = match.groups()
# In both cases, pass any extra_kwargs as **kwargs.
kwargs.update(self.default_args)
return ResolverMatch(self.callback, args, kwargs, self.name)
@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):
def __init__(self, regex, urlconf_name, default_kwargs=None, app_name=None, namespace=None):
LocaleRegexProvider.__init__(self, regex)
# urlconf_name is the dotted Python path to the module defining
# urlpatterns. It may also be an object with an urlpatterns attribute
# or urlpatterns itself.
self.urlconf_name = urlconf_name
self.callback = None
self.default_kwargs = default_kwargs or {}
self.namespace = namespace
self.app_name = app_name
self._reverse_dict = {}
self._namespace_dict = {}
self._app_dict = {}
# set of dotted paths to all functions and classes that are used in
# urlpatterns
self._callback_strs = set()
self._populated = False
def __repr__(self):
if isinstance(self.urlconf_name, list) and len(self.urlconf_name):
# Don't bother to output the whole list, it can be huge
urlconf_repr = '<%s list>' % self.urlconf_name[0].__class__.__name__
else:
urlconf_repr = repr(self.urlconf_name)
return str('<%s %s (%s:%s) %s>') % (
self.__class__.__name__, urlconf_repr, self.app_name,
self.namespace, self.regex.pattern)
def _populate(self):
lookups = MultiValueDict()
namespaces = {}
apps = {}
language_code = get_language()
for pattern in reversed(self.url_patterns):
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:]
if isinstance(pattern, RegexURLResolver):
if pattern.namespace:
namespaces[pattern.namespace] = (p_pattern, pattern)
if pattern.app_name:
apps.setdefault(pattern.app_name, []).append(pattern.namespace)
else:
parent_pat = pattern.regex.pattern
for name in pattern.reverse_dict:
for matches, pat, defaults in pattern.reverse_dict.getlist(name):
new_matches = normalize(parent_pat + pat)
lookups.appendlist(
name,
(
new_matches,
p_pattern + pat,
dict(defaults, **pattern.default_kwargs),
)
)
for namespace, (prefix, sub_pattern) in pattern.namespace_dict.items():
namespaces[namespace] = (p_pattern + prefix, sub_pattern)
for app_name, namespace_list in pattern.app_dict.items():
apps.setdefault(app_name, []).extend(namespace_list)
self._callback_strs.update(pattern._callback_strs)
else:
bits = normalize(p_pattern)
lookups.appendlist(pattern.callback, (bits, p_pattern, pattern.default_args))
if pattern.name is not None:
lookups.appendlist(pattern.name, (bits, p_pattern, pattern.default_args))
self._reverse_dict[language_code] = lookups
self._namespace_dict[language_code] = namespaces
self._app_dict[language_code] = apps
self._populated = True
@property
def reverse_dict(self):
language_code = get_language()
if language_code not in self._reverse_dict:
self._populate()
return self._reverse_dict[language_code]
@property
def namespace_dict(self):
language_code = get_language()
if language_code not in self._namespace_dict:
self._populate()
return self._namespace_dict[language_code]
@property
def app_dict(self):
language_code = get_language()
if language_code not in self._app_dict:
self._populate()
return self._app_dict[language_code]
def _is_callback(self, name):
if not self._populated:
self._populate()
return name in self._callback_strs
def resolve(self, path):
path = force_text(path) # path may be a reverse_lazy object
tried = []
match = self.regex.search(path)
if match:
new_path = path[match.end():]
for pattern in self.url_patterns:
try:
sub_match = pattern.resolve(new_path)
except Resolver404 as e:
sub_tried = e.args[0].get('tried')
if sub_tried is not None:
tried.extend([pattern] + t for t in sub_tried)
else:
tried.append([pattern])
else:
if sub_match:
# Merge captured arguments in match with submatch
sub_match_dict = dict(match.groupdict(), **self.default_kwargs)
sub_match_dict.update(sub_match.kwargs)
# If there are *any* named groups, ignore all non-named groups.
# Otherwise, pass all non-named arguments as positional arguments.
sub_match_args = sub_match.args
if not sub_match_dict:
sub_match_args = match.groups() + sub_match.args
return ResolverMatch(
sub_match.func,
sub_match_args,
sub_match_dict,
sub_match.url_name,
[self.app_name] + sub_match.app_names,
[self.namespace] + sub_match.namespaces
)
tried.append([pattern])
raise Resolver404({'tried': tried, 'path': new_path})
raise Resolver404({'path': path})
@cached_property
def urlconf_module(self):
if isinstance(self.urlconf_name, six.string_types):
return import_module(self.urlconf_name)
else:
return self.urlconf_name
@cached_property
def url_patterns(self):
# urlconf_module might be a valid set of patterns, so we default to it
patterns = getattr(self.urlconf_module, "urlpatterns", self.urlconf_module)
try:
iter(patterns)
except TypeError:
msg = (
"The included URLconf '{name}' does not appear to have any "
"patterns in it. If you see valid patterns in the file then "
"the issue is probably caused by a circular import."
)
raise ImproperlyConfigured(msg.format(name=self.urlconf_name))
return patterns
def resolve_error_handler(self, view_type):
callback = getattr(self.urlconf_module, 'handler%s' % view_type, None)
if not callback:
# No handler specified in file; use default
# Lazy import, since django.urls imports this file
from django.conf import urls
callback = getattr(urls, 'handler%s' % view_type)
return get_callable(callback), {}
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()!")
text_args = [force_text(v) for v in args]
text_kwargs = {k: force_text(v) for (k, v) in kwargs.items()}
if not self._populated:
self._populate()
possibilities = self.reverse_dict.getlist(lookup_view)
for possibility, pattern, defaults in possibilities:
for result, params in possibility:
if args:
if len(args) != len(params):
continue
candidate_subs = dict(zip(params, text_args))
else:
if (set(kwargs.keys()) | set(defaults.keys()) != set(params) |
set(defaults.keys())):
continue
matches = True
for k, v in defaults.items():
if kwargs.get(k, v) != v:
matches = False
break
if not matches:
continue
candidate_subs = text_kwargs
# WSGI provides decoded URLs, without %xx escapes, and the URL
# resolver operates on such URLs. First substitute arguments
# without quoting to build a decoded URL and look for a match.
# Then, if we have a match, redo the substitution with quoted
# arguments in order to return a properly encoded URL.
candidate_pat = _prefix.replace('%', '%%') + result
if re.search('^%s%s' % (re.escape(_prefix), pattern), candidate_pat % candidate_subs, re.UNICODE):
# safe characters from `pchar` definition of RFC 3986
url = urlquote(candidate_pat % candidate_subs, safe=RFC3986_SUBDELIMS + str('/~:@'))
# Don't allow construction of scheme relative urls.
if url.startswith('//'):
url = '/%%2F%s' % url[2:]
return url
# 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:
lookup_view_s = "%s.%s" % (m, n)
else:
lookup_view_s = lookup_view
patterns = [pattern for (possibility, pattern, defaults) in possibilities]
raise NoReverseMatch("Reverse for '%s' with arguments '%s' and keyword "
"arguments '%s' not found. %d pattern(s) tried: %s" %
(lookup_view_s, args, kwargs, len(patterns), patterns))
class LocaleRegexURLResolver(RegexURLResolver):
"""
A URL resolver that always matches the active language code as URL prefix.
Rather than taking a regex argument, we just override the ``regex``
function to always return the active language-code as regex.
"""
def __init__(self, urlconf_name, default_kwargs=None, app_name=None, namespace=None):
super(LocaleRegexURLResolver, self).__init__(
None, urlconf_name, default_kwargs, app_name, namespace)
@property
def regex(self):
language_code = get_language()
if language_code not in self._regex_dict:
regex_compiled = re.compile('^%s/' % language_code, re.UNICODE)
self._regex_dict[language_code] = regex_compiled
return self._regex_dict[language_code]
def resolve(path, urlconf=None):
if urlconf is None:
urlconf = get_urlconf()
return get_resolver(urlconf).resolve(path)
def reverse(viewname, urlconf=None, args=None, kwargs=None, current_app=None):
if urlconf is None:
urlconf = get_urlconf()
resolver = get_resolver(urlconf)
args = args or []
kwargs = kwargs or {}
prefix = get_script_prefix()
if not isinstance(viewname, six.string_types):
view = viewname
else:
parts = viewname.split(':')
parts.reverse()
view = parts[0]
path = parts[1:]
if current_app:
current_path = current_app.split(':')
current_path.reverse()
else:
current_path = None
resolved_path = []
ns_pattern = ''
while path:
ns = path.pop()
current_ns = current_path.pop() if current_path else None
# Lookup the name to see if it could be an app identifier
try:
app_list = resolver.app_dict[ns]
# Yes! Path part matches an app in the current Resolver
if current_ns and current_ns in app_list:
# If we are reversing for a particular app,
# use that namespace
ns = current_ns
elif ns not in app_list:
# The name isn't shared by one of the instances
# (i.e., the default) so just pick the first instance
# as the default.
ns = app_list[0]
except KeyError:
pass
if ns != current_ns:
current_path = None
try:
extra, resolver = resolver.namespace_dict[ns]
resolved_path.append(ns)
ns_pattern = ns_pattern + extra
except KeyError as key:
if resolved_path:
raise NoReverseMatch(
"%s is not a registered namespace inside '%s'" %
(key, ':'.join(resolved_path)))
else:
raise NoReverseMatch("%s is not a registered namespace" %
key)
if ns_pattern:
resolver = get_ns_resolver(ns_pattern, resolver)
return force_text(iri_to_uri(resolver._reverse_with_prefix(view, prefix, *args, **kwargs)))
reverse_lazy = lazy(reverse, six.text_type)
def clear_url_caches():
get_callable.cache_clear()
get_resolver.cache_clear()
get_ns_resolver.cache_clear()
def set_script_prefix(prefix):
"""
Sets the script prefix for the current thread.
"""
if not prefix.endswith('/'):
prefix += '/'
_prefixes.value = prefix
def get_script_prefix():
"""
Returns the currently active script prefix. Useful for client code that
wishes to construct their own URLs manually (although accessing the request
instance is normally going to be a lot cleaner).
"""
return getattr(_prefixes, "value", '/')
def clear_script_prefix():
"""
Unsets the script prefix for the current thread.
"""
try:
del _prefixes.value
except AttributeError:
pass
def set_urlconf(urlconf_name):
"""
Sets the URLconf for the current thread (overriding the default one in
settings). Set to None to revert back to the default.
"""
if urlconf_name:
_urlconfs.value = urlconf_name
else:
if hasattr(_urlconfs, "value"):
del _urlconfs.value
def get_urlconf(default=None):
"""
Returns the root URLconf to use for the current thread if it has been
changed from the default one.
"""
return getattr(_urlconfs, "value", default)
def is_valid_path(path, urlconf=None):
"""
Returns True if the given path resolves against the default URL resolver,
False otherwise.
This is a convenience method to make working with "is this a match?" cases
easier, avoiding unnecessarily indented try...except blocks.
"""
try:
resolve(path, urlconf)
return True
except Resolver404:
return False
def translate_url(url, lang_code):
"""
Given a URL (absolute or relative), try to get its translated version in
the `lang_code` language (either by i18n_patterns or by translated regex).
Return the original URL if no translated version is found.
"""
parsed = urlsplit(url)
try:
match = resolve(parsed.path)
except Resolver404:
pass
else:
to_be_reversed = "%s:%s" % (match.namespace, match.url_name) if match.namespace else match.url_name
with override(lang_code):
try:
url = reverse(to_be_reversed, args=match.args, kwargs=match.kwargs)
except NoReverseMatch:
pass
else:
url = urlunsplit((parsed.scheme, parsed.netloc, url, parsed.query, parsed.fragment))
return url

View File

@ -26,15 +26,15 @@ from django.db.models.fields.related import ( # NOQA isort:skip
def permalink(func): def permalink(func):
""" """
Decorator that calls urlresolvers.reverse() to return a URL using Decorator that calls urls.reverse() to return a URL using parameters
parameters returned by the decorated function "func". returned by the decorated function "func".
"func" should be a function that returns a tuple in one of the "func" should be a function that returns a tuple in one of the
following formats: following formats:
(viewname, viewargs) (viewname, viewargs)
(viewname, viewargs, viewkwargs) (viewname, viewargs, viewkwargs)
""" """
from django.core.urlresolvers import reverse from django.urls import reverse
@wraps(func) @wraps(func)
def inner(*args, **kwargs): def inner(*args, **kwargs):

View File

@ -3,9 +3,9 @@ import re
from django import http from django import http
from django.conf import settings from django.conf import settings
from django.core import urlresolvers
from django.core.exceptions import PermissionDenied from django.core.exceptions import PermissionDenied
from django.core.mail import mail_managers from django.core.mail import mail_managers
from django.urls import is_valid_path
from django.utils.cache import get_conditional_response, set_response_etag from django.utils.cache import get_conditional_response, set_response_etag
from django.utils.encoding import force_text from django.utils.encoding import force_text
from django.utils.six.moves.urllib.parse import urlparse from django.utils.six.moves.urllib.parse import urlparse
@ -74,8 +74,8 @@ class CommonMiddleware(object):
if settings.APPEND_SLASH and not request.get_full_path().endswith('/'): if settings.APPEND_SLASH and not request.get_full_path().endswith('/'):
urlconf = getattr(request, 'urlconf', None) urlconf = getattr(request, 'urlconf', None)
return ( return (
not urlresolvers.is_valid_path(request.path_info, urlconf) not is_valid_path(request.path_info, urlconf)
and urlresolvers.is_valid_path('%s/' % request.path_info, urlconf) and is_valid_path('%s/' % request.path_info, urlconf)
) )
return False return False

View File

@ -10,7 +10,7 @@ import logging
import re import re
from django.conf import settings from django.conf import settings
from django.core.urlresolvers import get_callable from django.urls import get_callable
from django.utils.cache import patch_vary_headers from django.utils.cache import patch_vary_headers
from django.utils.crypto import constant_time_compare, get_random_string from django.utils.crypto import constant_time_compare, get_random_string
from django.utils.encoding import force_text from django.utils.encoding import force_text

View File

@ -1,10 +1,10 @@
"This is the locale selecting middleware that will look at accept headers" "This is the locale selecting middleware that will look at accept headers"
from django.conf import settings from django.conf import settings
from django.core.urlresolvers import ( from django.http import HttpResponseRedirect
from django.urls import (
LocaleRegexURLResolver, get_resolver, get_script_prefix, is_valid_path, LocaleRegexURLResolver, get_resolver, get_script_prefix, is_valid_path,
) )
from django.http import HttpResponseRedirect
from django.utils import translation from django.utils import translation
from django.utils.cache import patch_vary_headers from django.utils.cache import patch_vary_headers
from django.utils.functional import cached_property from django.utils.functional import cached_property

View File

@ -3,7 +3,6 @@ This module collects helper functions and classes that "span" multiple levels
of MVC. In other words, these functions/classes introduce controlled coupling of MVC. In other words, these functions/classes introduce controlled coupling
for convenience's sake. for convenience's sake.
""" """
from django.core import urlresolvers
from django.db.models.base import ModelBase from django.db.models.base import ModelBase
from django.db.models.manager import Manager from django.db.models.manager import Manager
from django.db.models.query import QuerySet from django.db.models.query import QuerySet
@ -11,6 +10,7 @@ from django.http import (
Http404, HttpResponse, HttpResponsePermanentRedirect, HttpResponseRedirect, Http404, HttpResponse, HttpResponsePermanentRedirect, HttpResponseRedirect,
) )
from django.template import loader from django.template import loader
from django.urls import NoReverseMatch, reverse
from django.utils import six from django.utils import six
from django.utils.encoding import force_text from django.utils.encoding import force_text
from django.utils.functional import Promise from django.utils.functional import Promise
@ -43,8 +43,8 @@ def redirect(to, *args, **kwargs):
* A model: the model's `get_absolute_url()` function will be called. * A model: the model's `get_absolute_url()` function will be called.
* A view name, possibly with arguments: `urlresolvers.reverse()` will * A view name, possibly with arguments: `urls.reverse()` will be used
be used to reverse-resolve the name. to reverse-resolve the name.
* A URL, which will be used as-is for the redirect location. * A URL, which will be used as-is for the redirect location.
@ -123,8 +123,8 @@ def resolve_url(to, *args, **kwargs):
* A model: the model's `get_absolute_url()` function will be called. * A model: the model's `get_absolute_url()` function will be called.
* A view name, possibly with arguments: `urlresolvers.reverse()` will * A view name, possibly with arguments: `urls.reverse()` will be used
be used to reverse-resolve the name. to reverse-resolve the name.
* A URL, which will be returned as-is. * A URL, which will be returned as-is.
""" """
@ -144,8 +144,8 @@ def resolve_url(to, *args, **kwargs):
# Next try a reverse URL resolution. # Next try a reverse URL resolution.
try: try:
return urlresolvers.reverse(to, args=args, kwargs=kwargs) return reverse(to, args=args, kwargs=kwargs)
except urlresolvers.NoReverseMatch: except NoReverseMatch:
# If this is a callable, re-raise. # If this is a callable, re-raise.
if callable(to): if callable(to):
raise raise

View File

@ -426,7 +426,7 @@ class URLNode(Node):
self.asvar = asvar self.asvar = asvar
def render(self, context): def render(self, context):
from django.core.urlresolvers import reverse, NoReverseMatch from django.urls import reverse, NoReverseMatch
args = [arg.resolve(context) for arg in self.args] args = [arg.resolve(context) for arg in self.args]
kwargs = { kwargs = {
smart_text(k, 'ascii'): v.resolve(context) smart_text(k, 'ascii'): v.resolve(context)

View File

@ -11,7 +11,6 @@ from io import BytesIO
from django.apps import apps from django.apps import apps
from django.conf import settings from django.conf import settings
from django.core import urlresolvers
from django.core.handlers.base import BaseHandler from django.core.handlers.base import BaseHandler
from django.core.handlers.wsgi import ISO_8859_1, UTF_8, WSGIRequest from django.core.handlers.wsgi import ISO_8859_1, UTF_8, WSGIRequest
from django.core.signals import ( from django.core.signals import (
@ -22,6 +21,7 @@ from django.http import HttpRequest, QueryDict, SimpleCookie
from django.template import TemplateDoesNotExist from django.template import TemplateDoesNotExist
from django.test import signals from django.test import signals
from django.test.utils import ContextList from django.test.utils import ContextList
from django.urls import resolve
from django.utils import six from django.utils import six
from django.utils.encoding import force_bytes, force_str, uri_to_iri from django.utils.encoding import force_bytes, force_str, uri_to_iri
from django.utils.functional import SimpleLazyObject, curry from django.utils.functional import SimpleLazyObject, curry
@ -477,8 +477,7 @@ class Client(RequestFactory):
response.json = curry(self._parse_json, response) response.json = curry(self._parse_json, response)
# Attach the ResolverMatch instance to the response # Attach the ResolverMatch instance to the response
response.resolver_match = SimpleLazyObject( response.resolver_match = SimpleLazyObject(lambda: resolve(request['PATH_INFO']))
lambda: urlresolvers.resolve(request['PATH_INFO']))
# Flatten a single context. Not really necessary anymore thanks to # Flatten a single context. Not really necessary anymore thanks to
# the __getattr__ flattening in ContextList, but has some edge-case # the __getattr__ flattening in ContextList, but has some edge-case

View File

@ -145,7 +145,7 @@ def complex_setting_changed(**kwargs):
@receiver(setting_changed) @receiver(setting_changed)
def root_urlconf_changed(**kwargs): def root_urlconf_changed(**kwargs):
if kwargs['setting'] == 'ROOT_URLCONF': if kwargs['setting'] == 'ROOT_URLCONF':
from django.core.urlresolvers import clear_url_caches, set_urlconf from django.urls import clear_url_caches, set_urlconf
clear_url_caches() clear_url_caches()
set_urlconf(None) set_urlconf(None)

View File

@ -12,11 +12,11 @@ from django.apps import apps
from django.conf import UserSettingsHolder, settings from django.conf import UserSettingsHolder, settings
from django.core import mail from django.core import mail
from django.core.signals import request_started from django.core.signals import request_started
from django.core.urlresolvers import get_script_prefix, set_script_prefix
from django.db import reset_queries from django.db import reset_queries
from django.http import request from django.http import request
from django.template import Template from django.template import Template
from django.test.signals import setting_changed, template_rendered from django.test.signals import setting_changed, template_rendered
from django.urls import get_script_prefix, set_script_prefix
from django.utils import six from django.utils import six
from django.utils.decorators import ContextDecorator from django.utils.decorators import ContextDecorator
from django.utils.encoding import force_str from django.utils.encoding import force_str

20
django/urls/__init__.py Normal file
View File

@ -0,0 +1,20 @@
from .base import (
clear_script_prefix, clear_url_caches, get_script_prefix, get_urlconf,
is_valid_path, resolve, reverse, reverse_lazy, set_script_prefix,
set_urlconf, translate_url,
)
from .exceptions import NoReverseMatch, Resolver404
from .resolvers import (
LocaleRegexProvider, LocaleRegexURLResolver, RegexURLPattern,
RegexURLResolver, ResolverMatch, get_ns_resolver, get_resolver,
)
from .utils import get_callable, get_mod_func
__all__ = [
'LocaleRegexProvider', 'LocaleRegexURLResolver', 'NoReverseMatch',
'RegexURLPattern', 'RegexURLResolver', 'Resolver404', 'ResolverMatch',
'clear_script_prefix', 'clear_url_caches', 'get_callable', 'get_mod_func',
'get_ns_resolver', 'get_resolver', 'get_script_prefix', 'get_urlconf',
'is_valid_path', 'resolve', 'reverse', 'reverse_lazy', 'set_script_prefix',
'set_urlconf', 'translate_url',
]

185
django/urls/base.py Normal file
View File

@ -0,0 +1,185 @@
from __future__ import unicode_literals
from threading import local
from django.utils import six
from django.utils.encoding import force_text, iri_to_uri
from django.utils.functional import lazy
from django.utils.six.moves.urllib.parse import urlsplit, urlunsplit
from django.utils.translation import override
from .exceptions import NoReverseMatch, Resolver404
from .resolvers import get_ns_resolver, get_resolver
from .utils import get_callable
# SCRIPT_NAME prefixes for each thread are stored here. If there's no entry for
# the current thread (which is the only one we ever access), it is assumed to
# be empty.
_prefixes = local()
# Overridden URLconfs for each thread are stored here.
_urlconfs = local()
def resolve(path, urlconf=None):
if urlconf is None:
urlconf = get_urlconf()
return get_resolver(urlconf).resolve(path)
def reverse(viewname, urlconf=None, args=None, kwargs=None, current_app=None):
if urlconf is None:
urlconf = get_urlconf()
resolver = get_resolver(urlconf)
args = args or []
kwargs = kwargs or {}
prefix = get_script_prefix()
if not isinstance(viewname, six.string_types):
view = viewname
else:
parts = viewname.split(':')
parts.reverse()
view = parts[0]
path = parts[1:]
if current_app:
current_path = current_app.split(':')
current_path.reverse()
else:
current_path = None
resolved_path = []
ns_pattern = ''
while path:
ns = path.pop()
current_ns = current_path.pop() if current_path else None
# Lookup the name to see if it could be an app identifier.
try:
app_list = resolver.app_dict[ns]
# Yes! Path part matches an app in the current Resolver.
if current_ns and current_ns in app_list:
# If we are reversing for a particular app, use that
# namespace.
ns = current_ns
elif ns not in app_list:
# The name isn't shared by one of the instances (i.e.,
# the default) so pick the first instance as the default.
ns = app_list[0]
except KeyError:
pass
if ns != current_ns:
current_path = None
try:
extra, resolver = resolver.namespace_dict[ns]
resolved_path.append(ns)
ns_pattern = ns_pattern + extra
except KeyError as key:
if resolved_path:
raise NoReverseMatch(
"%s is not a registered namespace inside '%s'" %
(key, ':'.join(resolved_path))
)
else:
raise NoReverseMatch("%s is not a registered namespace" % key)
if ns_pattern:
resolver = get_ns_resolver(ns_pattern, resolver)
return force_text(iri_to_uri(resolver._reverse_with_prefix(view, prefix, *args, **kwargs)))
reverse_lazy = lazy(reverse, six.text_type)
def clear_url_caches():
get_callable.cache_clear()
get_resolver.cache_clear()
get_ns_resolver.cache_clear()
def set_script_prefix(prefix):
"""
Set the script prefix for the current thread.
"""
if not prefix.endswith('/'):
prefix += '/'
_prefixes.value = prefix
def get_script_prefix():
"""
Return the currently active script prefix. Useful for client code that
wishes to construct their own URLs manually (although accessing the request
instance is normally going to be a lot cleaner).
"""
return getattr(_prefixes, "value", '/')
def clear_script_prefix():
"""
Unset the script prefix for the current thread.
"""
try:
del _prefixes.value
except AttributeError:
pass
def set_urlconf(urlconf_name):
"""
Set the URLconf for the current thread (overriding the default one in
settings). If urlconf_name is None, revert back to the default.
"""
if urlconf_name:
_urlconfs.value = urlconf_name
else:
if hasattr(_urlconfs, "value"):
del _urlconfs.value
def get_urlconf(default=None):
"""
Return the root URLconf to use for the current thread if it has been
changed from the default one.
"""
return getattr(_urlconfs, "value", default)
def is_valid_path(path, urlconf=None):
"""
Return True if the given path resolves against the default URL resolver,
False otherwise. This is a convenience method to make working with "is
this a match?" cases easier, avoiding try...except blocks.
"""
from django.urls.base import resolve
try:
resolve(path, urlconf)
return True
except Resolver404:
return False
def translate_url(url, lang_code):
"""
Given a URL (absolute or relative), try to get its translated version in
the `lang_code` language (either by i18n_patterns or by translated regex).
Return the original URL if no translated version is found.
"""
from django.urls import resolve, reverse
parsed = urlsplit(url)
try:
match = resolve(parsed.path)
except Resolver404:
pass
else:
to_be_reversed = "%s:%s" % (match.namespace, match.url_name) if match.namespace else match.url_name
with override(lang_code):
try:
url = reverse(to_be_reversed, args=match.args, kwargs=match.kwargs)
except NoReverseMatch:
pass
else:
url = urlunsplit((parsed.scheme, parsed.netloc, url, parsed.query, parsed.fragment))
return url

11
django/urls/exceptions.py Normal file
View File

@ -0,0 +1,11 @@
from __future__ import unicode_literals
from django.http import Http404
class Resolver404(Http404):
pass
class NoReverseMatch(Exception):
pass

393
django/urls/resolvers.py Normal file
View File

@ -0,0 +1,393 @@
"""
This module converts requested URLs to callback view functions.
RegexURLResolver is the main class here. Its resolve() method takes a URL (as
a string) and returns a ResolverMatch object which provides access to all
attributes of the resolved URL match.
"""
from __future__ import unicode_literals
import functools
import re
from importlib import import_module
from django.core.exceptions import ImproperlyConfigured
from django.utils import lru_cache, six
from django.utils.datastructures import MultiValueDict
from django.utils.encoding import force_str, force_text
from django.utils.functional import cached_property
from django.utils.http import RFC3986_SUBDELIMS, urlquote
from django.utils.regex_helper import normalize
from django.utils.translation import get_language
from .exceptions import NoReverseMatch, Resolver404
from .utils import get_callable
class ResolverMatch(object):
def __init__(self, func, args, kwargs, url_name=None, app_names=None, namespaces=None):
self.func = func
self.args = args
self.kwargs = kwargs
self.url_name = url_name
# If a URLRegexResolver doesn't have a namespace or app_name, it passes
# in an empty value.
self.app_names = [x for x in app_names if x] if app_names else []
self.app_name = ':'.join(self.app_names)
self.namespaces = [x for x in namespaces if x] if namespaces else []
self.namespace = ':'.join(self.namespaces)
if not hasattr(func, '__name__'):
# A class-based view
self._func_path = '.'.join([func.__class__.__module__, func.__class__.__name__])
else:
# A function-based view
self._func_path = '.'.join([func.__module__, func.__name__])
view_path = url_name or self._func_path
self.view_name = ':'.join(self.namespaces + [view_path])
def __getitem__(self, index):
return (self.func, self.args, self.kwargs)[index]
def __repr__(self):
return "ResolverMatch(func=%s, args=%s, kwargs=%s, url_name=%s, app_names=%s, namespaces=%s)" % (
self._func_path, self.args, self.kwargs, self.url_name,
self.app_names, self.namespaces,
)
@lru_cache.lru_cache(maxsize=None)
def get_resolver(urlconf=None):
if urlconf is None:
from django.conf import settings
urlconf = settings.ROOT_URLCONF
return RegexURLResolver(r'^/', urlconf)
@lru_cache.lru_cache(maxsize=None)
def get_ns_resolver(ns_pattern, resolver):
# Build a namespaced resolver for the given parent URLconf pattern.
# This makes it possible to have captured parameters in the parent
# URLconf pattern.
ns_resolver = RegexURLResolver(ns_pattern, resolver.url_patterns)
return RegexURLResolver(r'^/', [ns_resolver])
class LocaleRegexProvider(object):
"""
A mixin to provide a default regex property which can vary by active
language.
"""
def __init__(self, regex):
# regex is either a string representing a regular expression, or a
# translatable string (using ugettext_lazy) representing a regular
# expression.
self._regex = regex
self._regex_dict = {}
@property
def regex(self):
"""
Return a compiled regular expression based on the activate language.
"""
language_code = get_language()
if language_code not in self._regex_dict:
regex = self._regex if isinstance(self._regex, six.string_types) else force_text(self._regex)
try:
compiled_regex = re.compile(regex, re.UNICODE)
except re.error as e:
raise ImproperlyConfigured(
'"%s" is not a valid regular expression: %s' %
(regex, six.text_type(e))
)
self._regex_dict[language_code] = compiled_regex
return self._regex_dict[language_code]
class RegexURLPattern(LocaleRegexProvider):
def __init__(self, regex, callback, default_args=None, name=None):
LocaleRegexProvider.__init__(self, regex)
self.callback = callback # the view
self.default_args = default_args or {}
self.name = name
def __repr__(self):
return force_str('<%s %s %s>' % (self.__class__.__name__, self.name, self.regex.pattern))
def resolve(self, path):
match = self.regex.search(path)
if match:
# If there are any named groups, use those as kwargs, ignoring
# non-named groups. Otherwise, pass all non-named arguments as
# positional arguments.
kwargs = match.groupdict()
args = () if kwargs else match.groups()
# In both cases, pass any extra_kwargs as **kwargs.
kwargs.update(self.default_args)
return ResolverMatch(self.callback, args, kwargs, self.name)
@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):
def __init__(self, regex, urlconf_name, default_kwargs=None, app_name=None, namespace=None):
LocaleRegexProvider.__init__(self, regex)
# urlconf_name is the dotted Python path to the module defining
# urlpatterns. It may also be an object with an urlpatterns attribute
# or urlpatterns itself.
self.urlconf_name = urlconf_name
self.callback = None
self.default_kwargs = default_kwargs or {}
self.namespace = namespace
self.app_name = app_name
self._reverse_dict = {}
self._namespace_dict = {}
self._app_dict = {}
# set of dotted paths to all functions and classes that are used in
# urlpatterns
self._callback_strs = set()
self._populated = False
def __repr__(self):
if isinstance(self.urlconf_name, list) and len(self.urlconf_name):
# Don't bother to output the whole list, it can be huge
urlconf_repr = '<%s list>' % self.urlconf_name[0].__class__.__name__
else:
urlconf_repr = repr(self.urlconf_name)
return str('<%s %s (%s:%s) %s>') % (
self.__class__.__name__, urlconf_repr, self.app_name,
self.namespace, self.regex.pattern,
)
def _populate(self):
lookups = MultiValueDict()
namespaces = {}
apps = {}
language_code = get_language()
for pattern in reversed(self.url_patterns):
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:]
if isinstance(pattern, RegexURLResolver):
if pattern.namespace:
namespaces[pattern.namespace] = (p_pattern, pattern)
if pattern.app_name:
apps.setdefault(pattern.app_name, []).append(pattern.namespace)
else:
parent_pat = pattern.regex.pattern
for name in pattern.reverse_dict:
for matches, pat, defaults in pattern.reverse_dict.getlist(name):
new_matches = normalize(parent_pat + pat)
lookups.appendlist(
name,
(
new_matches,
p_pattern + pat,
dict(defaults, **pattern.default_kwargs),
)
)
for namespace, (prefix, sub_pattern) in pattern.namespace_dict.items():
namespaces[namespace] = (p_pattern + prefix, sub_pattern)
for app_name, namespace_list in pattern.app_dict.items():
apps.setdefault(app_name, []).extend(namespace_list)
self._callback_strs.update(pattern._callback_strs)
else:
bits = normalize(p_pattern)
lookups.appendlist(pattern.callback, (bits, p_pattern, pattern.default_args))
if pattern.name is not None:
lookups.appendlist(pattern.name, (bits, p_pattern, pattern.default_args))
self._reverse_dict[language_code] = lookups
self._namespace_dict[language_code] = namespaces
self._app_dict[language_code] = apps
self._populated = True
@property
def reverse_dict(self):
language_code = get_language()
if language_code not in self._reverse_dict:
self._populate()
return self._reverse_dict[language_code]
@property
def namespace_dict(self):
language_code = get_language()
if language_code not in self._namespace_dict:
self._populate()
return self._namespace_dict[language_code]
@property
def app_dict(self):
language_code = get_language()
if language_code not in self._app_dict:
self._populate()
return self._app_dict[language_code]
def _is_callback(self, name):
if not self._populated:
self._populate()
return name in self._callback_strs
def resolve(self, path):
path = force_text(path) # path may be a reverse_lazy object
tried = []
match = self.regex.search(path)
if match:
new_path = path[match.end():]
for pattern in self.url_patterns:
try:
sub_match = pattern.resolve(new_path)
except Resolver404 as e:
sub_tried = e.args[0].get('tried')
if sub_tried is not None:
tried.extend([pattern] + t for t in sub_tried)
else:
tried.append([pattern])
else:
if sub_match:
# Merge captured arguments in match with submatch
sub_match_dict = dict(match.groupdict(), **self.default_kwargs)
sub_match_dict.update(sub_match.kwargs)
# If there are *any* named groups, ignore all non-named groups.
# Otherwise, pass all non-named arguments as positional arguments.
sub_match_args = sub_match.args
if not sub_match_dict:
sub_match_args = match.groups() + sub_match.args
return ResolverMatch(
sub_match.func,
sub_match_args,
sub_match_dict,
sub_match.url_name,
[self.app_name] + sub_match.app_names,
[self.namespace] + sub_match.namespaces,
)
tried.append([pattern])
raise Resolver404({'tried': tried, 'path': new_path})
raise Resolver404({'path': path})
@cached_property
def urlconf_module(self):
if isinstance(self.urlconf_name, six.string_types):
return import_module(self.urlconf_name)
else:
return self.urlconf_name
@cached_property
def url_patterns(self):
# urlconf_module might be a valid set of patterns, so we default to it
patterns = getattr(self.urlconf_module, "urlpatterns", self.urlconf_module)
try:
iter(patterns)
except TypeError:
msg = (
"The included URLconf '{name}' does not appear to have any "
"patterns in it. If you see valid patterns in the file then "
"the issue is probably caused by a circular import."
)
raise ImproperlyConfigured(msg.format(name=self.urlconf_name))
return patterns
def resolve_error_handler(self, view_type):
callback = getattr(self.urlconf_module, 'handler%s' % view_type, None)
if not callback:
# No handler specified in file; use lazy import, since
# django.conf.urls imports this file.
from django.conf import urls
callback = getattr(urls, 'handler%s' % view_type)
return get_callable(callback), {}
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()!")
text_args = [force_text(v) for v in args]
text_kwargs = {k: force_text(v) for (k, v) in kwargs.items()}
if not self._populated:
self._populate()
possibilities = self.reverse_dict.getlist(lookup_view)
for possibility, pattern, defaults in possibilities:
for result, params in possibility:
if args:
if len(args) != len(params):
continue
candidate_subs = dict(zip(params, text_args))
else:
if (set(kwargs.keys()) | set(defaults.keys()) != set(params) |
set(defaults.keys())):
continue
matches = True
for k, v in defaults.items():
if kwargs.get(k, v) != v:
matches = False
break
if not matches:
continue
candidate_subs = text_kwargs
# WSGI provides decoded URLs, without %xx escapes, and the URL
# resolver operates on such URLs. First substitute arguments
# without quoting to build a decoded URL and look for a match.
# Then, if we have a match, redo the substitution with quoted
# arguments in order to return a properly encoded URL.
candidate_pat = _prefix.replace('%', '%%') + result
if re.search('^%s%s' % (re.escape(_prefix), pattern), candidate_pat % candidate_subs, re.UNICODE):
# safe characters from `pchar` definition of RFC 3986
url = urlquote(candidate_pat % candidate_subs, safe=RFC3986_SUBDELIMS + str('/~:@'))
# Don't allow construction of scheme relative urls.
if url.startswith('//'):
url = '/%%2F%s' % url[2:]
return url
# 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:
lookup_view_s = "%s.%s" % (m, n)
else:
lookup_view_s = lookup_view
patterns = [pattern for (possibility, pattern, defaults) in possibilities]
raise NoReverseMatch(
"Reverse for '%s' with arguments '%s' and keyword "
"arguments '%s' not found. %d pattern(s) tried: %s" %
(lookup_view_s, args, kwargs, len(patterns), patterns)
)
class LocaleRegexURLResolver(RegexURLResolver):
"""
A URL resolver that always matches the active language code as URL prefix.
Rather than taking a regex argument, we just override the ``regex``
function to always return the active language-code as regex.
"""
def __init__(self, urlconf_name, default_kwargs=None, app_name=None, namespace=None):
super(LocaleRegexURLResolver, self).__init__(
None, urlconf_name, default_kwargs, app_name, namespace,
)
@property
def regex(self):
language_code = get_language()
if language_code not in self._regex_dict:
regex_compiled = re.compile('^%s/' % language_code, re.UNICODE)
self._regex_dict[language_code] = regex_compiled
return self._regex_dict[language_code]

64
django/urls/utils.py Normal file
View File

@ -0,0 +1,64 @@
from __future__ import unicode_literals
from importlib import import_module
from django.core.exceptions import ViewDoesNotExist
from django.utils import lru_cache, six
from django.utils.module_loading import module_has_submodule
@lru_cache.lru_cache(maxsize=None)
def get_callable(lookup_view):
"""
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, 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)
mod_name, func_name = get_mod_func(lookup_view)
if not func_name: # No '.' in lookup_view
raise ImportError("Could not import '%s'. The path must be fully qualified." % lookup_view)
try:
mod = import_module(mod_name)
except ImportError:
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)
)
else:
raise
else:
try:
view_func = getattr(mod, func_name)
except AttributeError:
raise ViewDoesNotExist(
"Could not import '%s'. View does not exist in module %s." %
(lookup_view, mod_name)
)
else:
if not callable(view_func):
raise ViewDoesNotExist(
"Could not import '%s.%s'. View is not callable." %
(mod_name, func_name)
)
return view_func
def get_mod_func(callback):
# Convert 'django.views.news.stories.story_detail' to
# ['django.views.news.stories', 'story_detail']
try:
dot = callback.rindex('.')
except ValueError:
return callback, ''
return callback[:dot], callback[dot + 1:]

View File

@ -5,10 +5,10 @@ import sys
import types import types
from django.conf import settings from django.conf import settings
from django.core.urlresolvers import Resolver404, resolve
from django.http import HttpResponse, HttpResponseNotFound from django.http import HttpResponse, HttpResponseNotFound
from django.template import Context, Engine, TemplateDoesNotExist from django.template import Context, Engine, TemplateDoesNotExist
from django.template.defaultfilters import force_escape, pprint from django.template.defaultfilters import force_escape, pprint
from django.urls import Resolver404, resolve
from django.utils import lru_cache, six, timezone from django.utils import lru_cache, six, timezone
from django.utils.datastructures import MultiValueDict from django.utils.datastructures import MultiValueDict
from django.utils.encoding import force_bytes, smart_text from django.utils.encoding import force_bytes, smart_text

View File

@ -5,8 +5,8 @@ from functools import update_wrapper
from django import http from django import http
from django.core.exceptions import ImproperlyConfigured from django.core.exceptions import ImproperlyConfigured
from django.core.urlresolvers import NoReverseMatch, reverse
from django.template.response import TemplateResponse from django.template.response import TemplateResponse
from django.urls import NoReverseMatch, reverse
from django.utils import six from django.utils import six
from django.utils.decorators import classonlymethod from django.utils.decorators import classonlymethod

View File

@ -6,8 +6,8 @@ import os
from django import http from django import http
from django.apps import apps from django.apps import apps
from django.conf import settings from django.conf import settings
from django.core.urlresolvers import translate_url
from django.template import Context, Engine from django.template import Context, Engine
from django.urls import translate_url
from django.utils import six from django.utils import six
from django.utils._os import upath from django.utils._os import upath
from django.utils.encoding import smart_text from django.utils.encoding import smart_text

View File

@ -262,7 +262,7 @@ already been configured).
So, if there is a module containing some code as follows:: So, if there is a module containing some code as follows::
from django.conf import settings from django.conf import settings
from django.core.urlresolvers import get_callable from django.urls import get_callable
default_foo_view = get_callable(settings.FOO_VIEW) default_foo_view = get_callable(settings.FOO_VIEW)

View File

@ -128,6 +128,8 @@ details on these changes.
* The ``shell --plain`` option will be removed. * The ``shell --plain`` option will be removed.
* The ``django.core.urlresolvers`` module will be removed.
.. _deprecation-removed-in-1.10: .. _deprecation-removed-in-1.10:
1.10 1.10
@ -152,8 +154,7 @@ details on these changes.
* Using an incorrect count of unpacked values in the ``for`` template tag * Using an incorrect count of unpacked values in the ``for`` template tag
will raise an exception rather than fail silently. will raise an exception rather than fail silently.
* The ability to :func:`~django.core.urlresolvers.reverse` URLs using a dotted * The ability to reverse URLs using a dotted Python path will be removed.
Python path will be removed.
* Support for :py:mod:`optparse` will be dropped for custom management commands * Support for :py:mod:`optparse` will be dropped for custom management commands
(replaced by :py:mod:`argparse`). (replaced by :py:mod:`argparse`).

View File

@ -56,7 +56,7 @@ To get from a URL to a view, Django uses what are known as 'URLconfs'. A
URLconf maps URL patterns (described as regular expressions) to views. URLconf maps URL patterns (described as regular expressions) to views.
This tutorial provides basic instruction in the use of URLconfs, and you can This tutorial provides basic instruction in the use of URLconfs, and you can
refer to :mod:`django.core.urlresolvers` for more information. refer to :mod:`django.urls` for more information.
Writing more views Writing more views
================== ==================

View File

@ -71,7 +71,7 @@ create a real version. Add the following to ``polls/views.py``:
from django.shortcuts import get_object_or_404, render from django.shortcuts import get_object_or_404, render
from django.http import HttpResponseRedirect, HttpResponse from django.http import HttpResponseRedirect, HttpResponse
from django.core.urlresolvers import reverse from django.urls import reverse
from .models import Choice, Question from .models import Choice, Question
# ... # ...
@ -124,13 +124,13 @@ This code includes a few things we haven't covered yet in this tutorial:
POST data. This tip isn't specific to Django; it's just good Web POST data. This tip isn't specific to Django; it's just good Web
development practice. development practice.
* We are using the :func:`~django.core.urlresolvers.reverse` function in the * We are using the :func:`~django.urls.reverse` function in the
:class:`~django.http.HttpResponseRedirect` constructor in this example. :class:`~django.http.HttpResponseRedirect` constructor in this example.
This function helps avoid having to hardcode a URL in the view function. This function helps avoid having to hardcode a URL in the view function.
It is given the name of the view that we want to pass control to and the It is given the name of the view that we want to pass control to and the
variable portion of the URL pattern that points to that view. In this variable portion of the URL pattern that points to that view. In this
case, using the URLconf we set up in :doc:`Tutorial 3 </intro/tutorial03>`, case, using the URLconf we set up in :doc:`Tutorial 3 </intro/tutorial03>`,
this :func:`~django.core.urlresolvers.reverse` call will return a string like this :func:`~django.urls.reverse` call will return a string like
:: ::
'/polls/3/results/' '/polls/3/results/'
@ -264,7 +264,7 @@ views and use Django's generic views instead. To do so, open the
from django.shortcuts import get_object_or_404, render from django.shortcuts import get_object_or_404, render
from django.http import HttpResponseRedirect from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse from django.urls import reverse
from django.views import generic from django.views import generic
from .models import Choice, Question from .models import Choice, Question

View File

@ -362,7 +362,7 @@ With that ready, we can ask the client to do some work for us::
404 404
>>> # on the other hand we should expect to find something at '/polls/' >>> # on the other hand we should expect to find something at '/polls/'
>>> # we'll use 'reverse()' rather than a hardcoded URL >>> # we'll use 'reverse()' rather than a hardcoded URL
>>> from django.core.urlresolvers import reverse >>> from django.urls import reverse
>>> response = client.get(reverse('polls:index')) >>> response = client.get(reverse('polls:index'))
>>> response.status_code >>> response.status_code
200 200
@ -447,7 +447,7 @@ Add the following to ``polls/tests.py``:
.. snippet:: .. snippet::
:filename: polls/tests.py :filename: polls/tests.py
from django.core.urlresolvers import reverse from django.urls import reverse
and we'll create a shortcut function to create questions as well as a new test and we'll create a shortcut function to create questions as well as a new test
class: class:

View File

@ -13,7 +13,7 @@ views for displaying drilldown pages for date-based data.
defined as follows in ``myapp/models.py``:: defined as follows in ``myapp/models.py``::
from django.db import models from django.db import models
from django.core.urlresolvers import reverse from django.urls import reverse
class Article(models.Model): class Article(models.Model):
title = models.CharField(max_length=200) title = models.CharField(max_length=200)

View File

@ -15,7 +15,7 @@ editing content:
Some of the examples on this page assume that an ``Author`` model has been Some of the examples on this page assume that an ``Author`` model has been
defined as follows in ``myapp/models.py``:: defined as follows in ``myapp/models.py``::
from django.core.urlresolvers import reverse from django.urls import reverse
from django.db import models from django.db import models
class Author(models.Model): class Author(models.Model):
@ -227,7 +227,7 @@ DeleteView
**Example myapp/views.py**:: **Example myapp/views.py**::
from django.views.generic.edit import DeleteView from django.views.generic.edit import DeleteView
from django.core.urlresolvers import reverse_lazy from django.urls import reverse_lazy
from myapp.models import Author from myapp.models import Author
class AuthorDelete(DeleteView): class AuthorDelete(DeleteView):

View File

@ -1252,7 +1252,7 @@ subclass::
For example:: For example::
from django.contrib import admin from django.contrib import admin
from django.core.urlresolvers import reverse from django.urls import reverse
class PersonAdmin(admin.ModelAdmin): class PersonAdmin(admin.ModelAdmin):
def view_on_site(self, obj): def view_on_site(self, obj):
@ -2883,9 +2883,9 @@ So - if you wanted to get a reference to the Change view for a particular
``Choice`` object (from the polls application) in the default admin, you would ``Choice`` object (from the polls application) in the default admin, you would
call:: call::
>>> from django.core import urlresolvers >>> from django.urls import reverse
>>> c = Choice.objects.get(...) >>> c = Choice.objects.get(...)
>>> change_url = urlresolvers.reverse('admin:polls_choice_change', args=(c.id,)) >>> change_url = reverse('admin:polls_choice_change', args=(c.id,))
This will find the first registered instance of the admin application This will find the first registered instance of the admin application
(whatever the instance name), and resolve to the view for changing (whatever the instance name), and resolve to the view for changing
@ -2896,8 +2896,7 @@ that instance as a ``current_app`` hint to the reverse call. For example,
if you specifically wanted the admin view from the admin instance named if you specifically wanted the admin view from the admin instance named
``custom``, you would need to call:: ``custom``, you would need to call::
>>> change_url = urlresolvers.reverse('admin:polls_choice_change', >>> change_url = reverse('admin:polls_choice_change', args=(c.id,), current_app='custom')
... args=(c.id,), current_app='custom')
For more details, see the documentation on :ref:`reversing namespaced URLs For more details, see the documentation on :ref:`reversing namespaced URLs
<topics-http-reversing-url-namespaces>`. <topics-http-reversing-url-namespaces>`.

View File

@ -300,13 +300,12 @@ Sitemap for static views
Often you want the search engine crawlers to index views which are neither Often you want the search engine crawlers to index views which are neither
object detail pages nor flatpages. The solution is to explicitly list URL object detail pages nor flatpages. The solution is to explicitly list URL
names for these views in ``items`` and call names for these views in ``items`` and call :func:`~django.urls.reverse` in
:func:`~django.core.urlresolvers.reverse` in the ``location`` method of the ``location`` method of the sitemap. For example::
the sitemap. For example::
# sitemaps.py # sitemaps.py
from django.contrib import sitemaps from django.contrib import sitemaps
from django.core.urlresolvers import reverse from django.urls import reverse
class StaticViewSitemap(sitemaps.Sitemap): class StaticViewSitemap(sitemaps.Sitemap):
priority = 0.5 priority = 0.5

View File

@ -53,7 +53,7 @@ This simple example, taken from a hypothetical police beat news site describes
a feed of the latest five news items:: a feed of the latest five news items::
from django.contrib.syndication.views import Feed from django.contrib.syndication.views import Feed
from django.core.urlresolvers import reverse from django.urls import reverse
from policebeat.models import NewsItem from policebeat.models import NewsItem
class LatestEntriesFeed(Feed): class LatestEntriesFeed(Feed):

View File

@ -84,7 +84,7 @@ Django core exception classes are defined in ``django.core.exceptions``.
.. exception:: ViewDoesNotExist .. exception:: ViewDoesNotExist
The :exc:`ViewDoesNotExist` exception is raised by The :exc:`ViewDoesNotExist` exception is raised by
:mod:`django.core.urlresolvers` when a requested view does not exist. :mod:`django.urls` when a requested view does not exist.
``MiddlewareNotUsed`` ``MiddlewareNotUsed``
--------------------- ---------------------
@ -142,12 +142,18 @@ or model are classified as ``NON_FIELD_ERRORS``. This constant is used
as a key in dictionaries that otherwise map fields to their respective as a key in dictionaries that otherwise map fields to their respective
list of errors. list of errors.
.. currentmodule:: django.core.urlresolvers .. currentmodule:: django.urls
URL Resolver exceptions URL Resolver exceptions
======================= =======================
URL Resolver exceptions are defined in ``django.core.urlresolvers``. URL Resolver exceptions are defined in ``django.urls``.
.. deprecated:: 1.10
In older versions, these exceptions are located in
``django.core.urlresolvers``. Importing from the old location will continue
to work until Django 2.0.
``Resolver404`` ``Resolver404``
--------------- ---------------
@ -155,18 +161,17 @@ URL Resolver exceptions are defined in ``django.core.urlresolvers``.
.. exception:: Resolver404 .. exception:: Resolver404
The :exc:`Resolver404` exception is raised by The :exc:`Resolver404` exception is raised by
:func:`django.core.urlresolvers.resolve()` if the path passed to :func:`~django.urls.resolve()` if the path passed to ``resolve()`` doesn't
``resolve()`` doesn't map to a view. It's a subclass of map to a view. It's a subclass of :class:`django.http.Http404`.
:class:`django.http.Http404`.
``NoReverseMatch`` ``NoReverseMatch``
------------------ ------------------
.. exception:: NoReverseMatch .. exception:: NoReverseMatch
The :exc:`NoReverseMatch` exception is raised by The :exc:`NoReverseMatch` exception is raised by :mod:`django.urls` when a
:mod:`django.core.urlresolvers` when a matching URL in your URLconf matching URL in your URLconf cannot be identified based on the parameters
cannot be identified based on the parameters supplied. supplied.
.. currentmodule:: django.db .. currentmodule:: django.db

View File

@ -672,14 +672,14 @@ For example::
def get_absolute_url(self): def get_absolute_url(self):
return "/people/%i/" % self.id return "/people/%i/" % self.id
(Whilst this code is correct and simple, it may not be the most portable way to While this code is correct and simple, it may not be the most portable way to
write this kind of method. The :func:`~django.core.urlresolvers.reverse` to write this kind of method. The :func:`~django.urls.reverse` function is
function is usually the best approach.) usually the best approach.
For example:: For example::
def get_absolute_url(self): def get_absolute_url(self):
from django.core.urlresolvers import reverse from django.urls import reverse
return reverse('people.views.details', args=[str(self.id)]) return reverse('people.views.details', args=[str(self.id)])
One place Django uses ``get_absolute_url()`` is in the admin app. If an object One place Django uses ``get_absolute_url()`` is in the admin app. If an object

View File

@ -160,11 +160,11 @@ All attributes should be considered read-only, unless stated otherwise.
.. attribute:: HttpRequest.resolver_match .. attribute:: HttpRequest.resolver_match
An instance of :class:`~django.core.urlresolvers.ResolverMatch` representing An instance of :class:`~django.urls.ResolverMatch` representing the
the resolved url. This attribute is only set after url resolving took place, resolved URL. This attribute is only set after URL resolving took place,
which means it's available in all views but not in middleware methods which which means it's available in all views but not in middleware methods
are executed before url resolving takes place (like ``process_request``, you which are executed before URL resolving takes place (like
can use ``process_view`` instead). ``process_request()``, you can use ``process_view()`` instead).
Attributes set by application code Attributes set by application code
---------------------------------- ----------------------------------
@ -175,7 +175,7 @@ application.
.. attribute:: HttpRequest.current_app .. attribute:: HttpRequest.current_app
The :ttag:`url` template tag will use its value as the ``current_app`` The :ttag:`url` template tag will use its value as the ``current_app``
argument to :func:`~django.core.urlresolvers.reverse()`. argument to :func:`~django.urls.reverse()`.
.. attribute:: HttpRequest.urlconf .. attribute:: HttpRequest.urlconf

View File

@ -1024,8 +1024,8 @@ such as this:
The template tag will output the string ``/clients/client/123/``. The template tag will output the string ``/clients/client/123/``.
Note that if the URL you're reversing doesn't exist, you'll get an Note that if the URL you're reversing doesn't exist, you'll get an
:exc:`~django.core.urlresolvers.NoReverseMatch` exception raised, which will :exc:`~django.urls.NoReverseMatch` exception raised, which will cause your
cause your site to display an error page. site to display an error page.
If you'd like to retrieve a URL without displaying it, you can use a slightly If you'd like to retrieve a URL without displaying it, you can use a slightly
different call:: different call::

View File

@ -290,8 +290,8 @@ Taking care in ``get_absolute_url()``
URLs can only contain ASCII characters. If you're constructing a URL from URLs can only contain ASCII characters. If you're constructing a URL from
pieces of data that might be non-ASCII, be careful to encode the results in a pieces of data that might be non-ASCII, be careful to encode the results in a
way that is suitable for a URL. The :func:`~django.core.urlresolvers.reverse` way that is suitable for a URL. The :func:`~django.urls.reverse` function
function handles this for you automatically. handles this for you automatically.
If you're constructing a URL manually (i.e., *not* using the ``reverse()`` If you're constructing a URL manually (i.e., *not* using the ``reverse()``
function), you'll need to take care of the encoding yourself. In this case, function), you'll need to take care of the encoding yourself. In this case,

View File

@ -1,8 +1,14 @@
============================================== =================================
``django.core.urlresolvers`` utility functions ``django.urls`` utility functions
============================================== =================================
.. module:: django.core.urlresolvers .. module:: django.urls
.. deprecated:: 1.10
In older versions, these functions are located in
``django.core.urlresolvers``. Importing from the old location will continue
to work until Django 2.0.
reverse() reverse()
--------- ---------
@ -31,7 +37,7 @@ you can use any of the following to reverse the URL::
If the URL accepts arguments, you may pass them in ``args``. For example:: If the URL accepts arguments, you may pass them in ``args``. For example::
from django.core.urlresolvers import reverse from django.urls import reverse
def myview(request): def myview(request):
return HttpResponseRedirect(reverse('arch-summary', args=[1945])) return HttpResponseRedirect(reverse('arch-summary', args=[1945]))
@ -44,7 +50,7 @@ You can also pass ``kwargs`` instead of ``args``. For example::
``args`` and ``kwargs`` cannot be passed to ``reverse()`` at the same time. ``args`` and ``kwargs`` cannot be passed to ``reverse()`` at the same time.
If no match can be made, ``reverse()`` raises a If no match can be made, ``reverse()`` raises a
:class:`~django.core.urlresolvers.NoReverseMatch` exception. :class:`~django.urls.NoReverseMatch` exception.
The ``reverse()`` function can reverse a large variety of regular expression The ``reverse()`` function can reverse a large variety of regular expression
patterns for URLs, but not every possible one. The main restriction at the patterns for URLs, but not every possible one. The main restriction at the
@ -103,13 +109,12 @@ corresponding view functions. It has the following signature:
.. function:: resolve(path, urlconf=None) .. function:: resolve(path, urlconf=None)
``path`` is the URL path you want to resolve. As with ``path`` is the URL path you want to resolve. As with
:func:`~django.core.urlresolvers.reverse`, you don't need to :func:`~django.urls.reverse`, you don't need to worry about the ``urlconf``
worry about the ``urlconf`` parameter. The function returns a parameter. The function returns a :class:`ResolverMatch` object that allows you
:class:`ResolverMatch` object that allows you to access various metadata about the resolved URL.
to access various meta-data about the resolved URL.
If the URL does not resolve, the function raises a If the URL does not resolve, the function raises a
:exc:`~django.core.urlresolvers.Resolver404` exception (a subclass of :exc:`~django.urls.Resolver404` exception (a subclass of
:class:`~django.http.Http404`) . :class:`~django.http.Http404`) .
.. class:: ResolverMatch .. class:: ResolverMatch
@ -175,10 +180,10 @@ A :class:`ResolverMatch` object can also be assigned to a triple::
func, args, kwargs = resolve('/some/path/') func, args, kwargs = resolve('/some/path/')
One possible use of :func:`~django.core.urlresolvers.resolve` would be to test One possible use of :func:`~django.urls.resolve` would be to test whether a
whether a view would raise a ``Http404`` error before redirecting to it:: view would raise a ``Http404`` error before redirecting to it::
from django.core.urlresolvers import resolve from django.urls import resolve
from django.http import HttpResponseRedirect, Http404 from django.http import HttpResponseRedirect, Http404
from django.utils.six.moves.urllib.parse import urlparse from django.utils.six.moves.urllib.parse import urlparse
@ -202,12 +207,11 @@ get_script_prefix()
.. function:: get_script_prefix() .. function:: get_script_prefix()
Normally, you should always use :func:`~django.core.urlresolvers.reverse` to Normally, you should always use :func:`~django.urls.reverse` to define URLs
define URLs within your application. However, if your application constructs within your application. However, if your application constructs part of the
part of the URL hierarchy itself, you may occasionally need to generate URLs. URL hierarchy itself, you may occasionally need to generate URLs. In that
In that case, you need to be able to find the base URL of the Django project case, you need to be able to find the base URL of the Django project within
within its Web server (normally, :func:`~django.core.urlresolvers.reverse` its Web server (normally, :func:`~django.urls.reverse` takes care of this for
takes care of this for you). In that case, you can call you). In that case, you can call ``get_script_prefix()``, which will return
``get_script_prefix()``, which will return the script prefix portion of the URL the script prefix portion of the URL for your Django project. If your Django
for your Django project. If your Django project is at the root of its web project is at the root of its web server, this is always ``"/"``.
server, this is always ``"/"``.

View File

@ -380,11 +380,11 @@ Other new features and changes introduced since Django 1.0 include:
order to allow fine-grained control of when and where the CSRF processing order to allow fine-grained control of when and where the CSRF processing
takes place. takes place.
* :func:`~django.core.urlresolvers.reverse` and code which uses it (e.g., the * ``reverse()`` and code which uses it (e.g., the ``{% url %}`` template tag)
``{% url %}`` template tag) now works with URLs in Django's administrative now works with URLs in Django's administrative site, provided that the admin
site, provided that the admin URLs are set up via ``include(admin.site.urls)`` URLs are set up via ``include(admin.site.urls)`` (sending admin requests to
(sending admin requests to the ``admin.site.root`` view still works, but URLs the ``admin.site.root`` view still works, but URLs in the admin will not be
in the admin will not be "reversible" when configured this way). "reversible" when configured this way).
* The ``include()`` function in Django URLconf modules can now accept sequences * The ``include()`` function in Django URLconf modules can now accept sequences
of URL patterns (generated by ``patterns()``) in addition to module names. of URL patterns (generated by ``patterns()``) in addition to module names.

View File

@ -460,6 +460,9 @@ Miscellaneous
* The ``shell --plain`` option is deprecated in favor of ``-i python`` or * The ``shell --plain`` option is deprecated in favor of ``-i python`` or
``--interface python``. ``--interface python``.
* Importing from the ``django.core.urlresolvers`` module is deprecated in
favor of its new location, :mod:`django.urls`.
.. _removed-features-1.10: .. _removed-features-1.10:
Features removed in 1.10 Features removed in 1.10
@ -485,8 +488,8 @@ removed in Django 1.10 (please see the :ref:`deprecation timeline
* Using an incorrect count of unpacked values in the ``for`` template tag * Using an incorrect count of unpacked values in the ``for`` template tag
raises an exception rather than failing silently. raises an exception rather than failing silently.
* The ability to :func:`~django.core.urlresolvers.reverse` URLs using a dotted * The ability to :func:`~django.urls.reverse` URLs using a dotted Python path
Python path is removed. is removed.
* Support for ``optparse`` is dropped for custom management commands. * Support for ``optparse`` is dropped for custom management commands.

View File

@ -16,14 +16,12 @@ Django's URL handling is based on a mapping of regex patterns
consists of matching a requested URL against those patterns to consists of matching a requested URL against those patterns to
determine the appropriate view to invoke. determine the appropriate view to invoke.
Django also provides a convenience function -- Django also provides a convenience function -- ``reverse()`` -- which performs
:func:`~django.core.urlresolvers.reverse` -- which performs this process this process in the opposite direction. The ``reverse()`` function takes
in the opposite direction. The ``reverse()`` function takes information about a view and returns a URL which would invoke that view. Use
information about a view and returns a URL which would invoke that of ``reverse()`` is encouraged for application developers, as the output of
view. Use of ``reverse()`` is encouraged for application developers, ``reverse()`` is always based on the current URL patterns, meaning developers
as the output of ``reverse()`` is always based on the current URL do not need to change other code when making changes to URLs.
patterns, meaning developers do not need to change other code when
making changes to URLs.
One argument signature for ``reverse()`` is to pass a dotted Python One argument signature for ``reverse()`` is to pass a dotted Python
path to the desired view. In this situation, Django will import the path to the desired view. In this situation, Django will import the

View File

@ -9,6 +9,5 @@ Django 1.4.12 fixes a regression in the 1.4.11 security release.
Bugfixes Bugfixes
======== ========
* Restored the ability to :meth:`~django.core.urlresolvers.reverse` views * Restored the ability to ``reverse()`` views created using
created using :func:`functools.partial()` :func:`functools.partial()` (:ticket:`22486`).
(:ticket:`22486`)

View File

@ -6,8 +6,8 @@ Django 1.4.14 release notes
Django 1.4.14 fixes several security issues in 1.4.13. Django 1.4.14 fixes several security issues in 1.4.13.
:func:`~django.core.urlresolvers.reverse()` could generate URLs pointing to other hosts ``reverse()`` could generate URLs pointing to other hosts
======================================================================================= =========================================================
In certain situations, URL reversing could generate scheme-relative URLs (URLs In certain situations, URL reversing could generate scheme-relative URLs (URLs
starting with two slashes), which could unexpectedly redirect a user to a starting with two slashes), which could unexpectedly redirect a user to a

View File

@ -371,8 +371,8 @@ Django 1.4 to store the wizard's state in the user's cookies.
``reverse_lazy`` ``reverse_lazy``
~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~
A lazily evaluated version of :func:`django.core.urlresolvers.reverse` was A lazily evaluated version of ``reverse()`` was added to allow using URL
added to allow using URL reversals before the project's URLconf gets loaded. reversals before the project's URLconf gets loaded.
Translating URL patterns Translating URL patterns
~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -15,14 +15,12 @@ Django's URL handling is based on a mapping of regex patterns
consists of matching a requested URL against those patterns to consists of matching a requested URL against those patterns to
determine the appropriate view to invoke. determine the appropriate view to invoke.
Django also provides a convenience function -- Django also provides a convenience function -- ``reverse()`` -- which performs
:func:`~django.core.urlresolvers.reverse` -- which performs this process this process in the opposite direction. The ``reverse()`` function takes
in the opposite direction. The ``reverse()`` function takes information about a view and returns a URL which would invoke that view. Use
information about a view and returns a URL which would invoke that of ``reverse()`` is encouraged for application developers, as the output of
view. Use of ``reverse()`` is encouraged for application developers, ``reverse()`` is always based on the current URL patterns, meaning developers
as the output of ``reverse()`` is always based on the current URL do not need to change other code when making changes to URLs.
patterns, meaning developers do not need to change other code when
making changes to URLs.
One argument signature for ``reverse()`` is to pass a dotted Python One argument signature for ``reverse()`` is to pass a dotted Python
path to the desired view. In this situation, Django will import the path to the desired view. In this situation, Django will import the

View File

@ -9,5 +9,5 @@ Django 1.5.7 fixes a regression in the 1.5.6 security release.
Bugfixes Bugfixes
======== ========
* Restored the ability to :meth:`~django.core.urlresolvers.reverse` views * Restored the ability to ``reverse()`` views created using
created using :func:`functools.partial()` (:ticket:`22486`). :func:`functools.partial()` (:ticket:`22486`).

View File

@ -6,8 +6,8 @@ Django 1.5.9 release notes
Django 1.5.9 fixes several security issues in 1.5.8. Django 1.5.9 fixes several security issues in 1.5.8.
:func:`~django.core.urlresolvers.reverse()` could generate URLs pointing to other hosts ``reverse()`` could generate URLs pointing to other hosts
======================================================================================= =========================================================
In certain situations, URL reversing could generate scheme-relative URLs (URLs In certain situations, URL reversing could generate scheme-relative URLs (URLs
starting with two slashes), which could unexpectedly redirect a user to a starting with two slashes), which could unexpectedly redirect a user to a

View File

@ -293,8 +293,8 @@ Django 1.5 also includes several smaller improvements worth noting:
objects fetched into memory. See :meth:`QuerySet.delete() objects fetched into memory. See :meth:`QuerySet.delete()
<django.db.models.query.QuerySet.delete>` for details. <django.db.models.query.QuerySet.delete>` for details.
* An instance of :class:`~django.core.urlresolvers.ResolverMatch` is stored on * An instance of ``ResolverMatch`` is stored on the request as
the request as ``resolver_match``. ``resolver_match``.
* By default, all logging messages reaching the ``django`` logger when * By default, all logging messages reaching the ``django`` logger when
:setting:`DEBUG` is ``True`` are sent to the console (unless you redefine the :setting:`DEBUG` is ``True`` are sent to the console (unless you redefine the

View File

@ -15,14 +15,12 @@ Django's URL handling is based on a mapping of regex patterns
consists of matching a requested URL against those patterns to consists of matching a requested URL against those patterns to
determine the appropriate view to invoke. determine the appropriate view to invoke.
Django also provides a convenience function -- Django also provides a convenience function -- ``reverse()`` -- which performs
:func:`~django.core.urlresolvers.reverse` -- which performs this process this process in the opposite direction. The ``reverse()`` function takes
in the opposite direction. The ``reverse()`` function takes information about a view and returns a URL which would invoke that view. Use
information about a view and returns a URL which would invoke that of ``reverse()`` is encouraged for application developers, as the output of
view. Use of ``reverse()`` is encouraged for application developers, ``reverse()`` is always based on the current URL patterns, meaning developers
as the output of ``reverse()`` is always based on the current URL do not need to change other code when making changes to URLs.
patterns, meaning developers do not need to change other code when
making changes to URLs.
One argument signature for ``reverse()`` is to pass a dotted Python One argument signature for ``reverse()`` is to pass a dotted Python
path to the desired view. In this situation, Django will import the path to the desired view. In this situation, Django will import the

View File

@ -13,10 +13,8 @@ Bugfixes
cookie format of Django 1.4 and earlier to facilitate upgrading to 1.6 from cookie format of Django 1.4 and earlier to facilitate upgrading to 1.6 from
1.4 (:ticket:`22426`). 1.4 (:ticket:`22426`).
* Restored the ability to :meth:`~django.core.urlresolvers.reverse` views * Restored the ability to ``reverse()`` views created using
created using :func:`functools.partial()` :func:`functools.partial()` (:ticket:`22486`).
(:ticket:`22486`).
* Fixed the ``object_id`` of the ``LogEntry`` that's created after a user * Fixed the ``object_id`` of the ``LogEntry`` that's created after a user
password change in the admin password change in the admin (:ticket:`22515`).
(:ticket:`22515`).

View File

@ -6,8 +6,8 @@ Django 1.6.6 release notes
Django 1.6.6 fixes several security issues and bugs in 1.6.5. Django 1.6.6 fixes several security issues and bugs in 1.6.5.
:func:`~django.core.urlresolvers.reverse()` could generate URLs pointing to other hosts ``reverse()`` could generate URLs pointing to other hosts
======================================================================================= =========================================================
In certain situations, URL reversing could generate scheme-relative URLs (URLs In certain situations, URL reversing could generate scheme-relative URLs (URLs
starting with two slashes), which could unexpectedly redirect a user to a starting with two slashes), which could unexpectedly redirect a user to a

View File

@ -583,16 +583,17 @@ be at the end of a line. If they are not, the comments are ignored and
{{ title }}{# Translators: Extracted and associated with 'Welcome' below #} {{ title }}{# Translators: Extracted and associated with 'Welcome' below #}
<h1>{% trans "Welcome" %}</h1> <h1>{% trans "Welcome" %}</h1>
Quoting in :func:`~django.core.urlresolvers.reverse` Quoting in ``reverse()``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~
When reversing URLs, Django didn't apply :func:`~django.utils.http.urlquote` When reversing URLs, Django didn't apply :func:`~django.utils.http.urlquote`
to arguments before interpolating them in URL patterns. This bug is fixed in to arguments before interpolating them in URL patterns. This bug is fixed in
Django 1.6. If you worked around this bug by applying URL quoting before Django 1.6. If you worked around this bug by applying URL quoting before
passing arguments to :func:`~django.core.urlresolvers.reverse`, this may passing arguments to ``reverse()``, this may result in double-quoting. If this
result in double-quoting. If this happens, simply remove the URL quoting from happens, simply remove the URL quoting from your code. You will also have to
your code. You will also have to replace special characters in URLs used in replace special characters in URLs used in
:func:`~django.test.SimpleTestCase.assertRedirects` with their encoded versions. :func:`~django.test.SimpleTestCase.assertRedirects` with their encoded
versions.
Storage of IP addresses in the comments app Storage of IP addresses in the comments app
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -902,12 +903,12 @@ Miscellaneous
stored as ``null``. Previously, storing a ``blank`` value in a field which stored as ``null``. Previously, storing a ``blank`` value in a field which
did not allow ``null`` would cause a database exception at runtime. did not allow ``null`` would cause a database exception at runtime.
* If a :class:`~django.core.urlresolvers.NoReverseMatch` exception is raised * If a ``NoReverseMatch`` exception is raised from a method when rendering a
from a method when rendering a template, it is not silenced. For example, template, it is not silenced. For example, ``{{ obj.view_href }}`` will
``{{ obj.view_href }}`` will cause template rendering to fail if cause template rendering to fail if ``view_href()`` raises
``view_href()`` raises ``NoReverseMatch``. There is no change to the ``NoReverseMatch``. There is no change to the :ttag:`{% url %}<url>` tag, it
:ttag:`{% url %}<url>` tag, it causes template rendering to fail like always causes template rendering to fail like always when ``NoReverseMatch`` is
when ``NoReverseMatch`` is raised. raised.
* :meth:`django.test.Client.logout` now calls * :meth:`django.test.Client.logout` now calls
:meth:`django.contrib.auth.logout` which will send the :meth:`django.contrib.auth.logout` which will send the

View File

@ -82,8 +82,7 @@ Bugfixes
(:ticket:`23815`). (:ticket:`23815`).
* Fixed a crash in the ``django.contrib.auth.redirect_to_login`` view when * Fixed a crash in the ``django.contrib.auth.redirect_to_login`` view when
passing a :func:`~django.core.urlresolvers.reverse_lazy` result on Python 3 passing a ``reverse_lazy()`` result on Python 3 (:ticket:`24097`).
(:ticket:`24097`).
* Added correct formats for Greek (``el``) (:ticket:`23967`). * Added correct formats for Greek (``el``) (:ticket:`23967`).

View File

@ -1112,9 +1112,8 @@ Miscellaneous
* The default max size of the Oracle test tablespace has increased from 300M * The default max size of the Oracle test tablespace has increased from 300M
(or 200M, before 1.7.2) to 500M. (or 200M, before 1.7.2) to 500M.
* :func:`~django.core.urlresolvers.reverse` and * ``reverse()`` and ``reverse_lazy()`` now return Unicode strings instead of
:func:`~django.core.urlresolvers.reverse_lazy` now return Unicode strings byte strings.
instead of byte strings.
* The ``CacheClass`` shim has been removed from all cache backends. * The ``CacheClass`` shim has been removed from all cache backends.
These aliases were provided for backwards compatibility with Django 1.3. These aliases were provided for backwards compatibility with Django 1.3.
@ -1334,8 +1333,8 @@ Using an incorrect count of unpacked values in the :ttag:`for` template tag
Using an incorrect count of unpacked values in :ttag:`for` tag will raise an Using an incorrect count of unpacked values in :ttag:`for` tag will raise an
exception rather than fail silently in Django 1.10. exception rather than fail silently in Django 1.10.
Passing a dotted path to :func:`~django.core.urlresolvers.reverse()` and :ttag:`url` Passing a dotted path to ``reverse()`` and :ttag:`url`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Reversing URLs by Python path is an expensive operation as it causes the Reversing URLs by Python path is an expensive operation as it causes the
path being reversed to be imported. This behavior has also resulted in a path being reversed to be imported. This behavior has also resulted in a

View File

@ -1083,12 +1083,10 @@ Miscellaneous
:attr:`~django.test.SimpleTestCase.allow_database_queries` class attribute :attr:`~django.test.SimpleTestCase.allow_database_queries` class attribute
to ``True`` on your test class. to ``True`` on your test class.
* :attr:`ResolverMatch.app_name * ``ResolverMatch.app_name`` was changed to contain the full namespace path in
<django.core.urlresolvers.ResolverMatch.app_name>` was changed to contain the case of nested namespaces. For consistency with
the full namespace path in the case of nested namespaces. For consistency ``ResolverMatch.namespace``, the empty value is now an empty string instead
with :attr:`ResolverMatch.namespace of ``None``.
<django.core.urlresolvers.ResolverMatch.namespace>`, the empty value is now
an empty string instead of ``None``.
* For security hardening, session keys must be at least 8 characters. * For security hardening, session keys must be at least 8 characters.

View File

@ -98,7 +98,7 @@ First we need to add :meth:`~django.db.models.Model.get_absolute_url()` to our
.. snippet:: .. snippet::
:filename: models.py :filename: models.py
from django.core.urlresolvers import reverse from django.urls import reverse
from django.db import models from django.db import models
class Author(models.Model): class Author(models.Model):
@ -115,7 +115,7 @@ here; we don't have to write any logic ourselves:
:filename: views.py :filename: views.py
from django.views.generic.edit import CreateView, UpdateView, DeleteView from django.views.generic.edit import CreateView, UpdateView, DeleteView
from django.core.urlresolvers import reverse_lazy from django.urls import reverse_lazy
from myapp.models import Author from myapp.models import Author
class AuthorCreate(CreateView): class AuthorCreate(CreateView):
@ -131,8 +131,8 @@ here; we don't have to write any logic ourselves:
success_url = reverse_lazy('author-list') success_url = reverse_lazy('author-list')
.. note:: .. note::
We have to use :func:`~django.core.urlresolvers.reverse_lazy` here, not We have to use :func:`~django.urls.reverse_lazy` here, not just
just ``reverse`` as the urls are not loaded when the file is imported. ``reverse()`` as the urls are not loaded when the file is imported.
The ``fields`` attribute works the same way as the ``fields`` attribute on the The ``fields`` attribute works the same way as the ``fields`` attribute on the
inner ``Meta`` class on :class:`~django.forms.ModelForm`. Unless you define the inner ``Meta`` class on :class:`~django.forms.ModelForm`. Unless you define the

View File

@ -225,7 +225,7 @@ We'll demonstrate this with the ``Author`` model we used in the
:filename: views.py :filename: views.py
from django.http import HttpResponseForbidden, HttpResponseRedirect from django.http import HttpResponseForbidden, HttpResponseRedirect
from django.core.urlresolvers import reverse from django.urls import reverse
from django.views.generic import View from django.views.generic import View
from django.views.generic.detail import SingleObjectMixin from django.views.generic.detail import SingleObjectMixin
from books.models import Author from books.models import Author
@ -445,7 +445,7 @@ Our new ``AuthorDetail`` looks like this::
from django import forms from django import forms
from django.http import HttpResponseForbidden from django.http import HttpResponseForbidden
from django.core.urlresolvers import reverse from django.urls import reverse
from django.views.generic import DetailView from django.views.generic import DetailView
from django.views.generic.edit import FormMixin from django.views.generic.edit import FormMixin
from books.models import Author from books.models import Author
@ -541,7 +541,7 @@ can find the author we're talking about, and we have to remember to set
``template_name`` to ensure that form errors will render the same ``template_name`` to ensure that form errors will render the same
template as ``AuthorDisplay`` is using on ``GET``:: template as ``AuthorDisplay`` is using on ``GET``::
from django.core.urlresolvers import reverse from django.urls import reverse
from django.http import HttpResponseForbidden from django.http import HttpResponseForbidden
from django.views.generic import FormView from django.views.generic import FormView
from django.views.generic.detail import SingleObjectMixin from django.views.generic.detail import SingleObjectMixin

View File

@ -103,9 +103,8 @@ This example is equivalent to::
* A model: the model's :meth:`~django.db.models.Model.get_absolute_url()` * A model: the model's :meth:`~django.db.models.Model.get_absolute_url()`
function will be called. function will be called.
* A view name, possibly with arguments: :func:`urlresolvers.reverse * A view name, possibly with arguments: :func:`~django.urls.reverse` will be
<django.core.urlresolvers.reverse>` will be used to reverse-resolve the used to reverse-resolve the name.
name.
* An absolute or relative URL, which will be used as-is for the redirect * An absolute or relative URL, which will be used as-is for the redirect
location. location.
@ -131,7 +130,7 @@ You can use the :func:`redirect` function in a number of ways.
2. By passing the name of a view and optionally some positional or 2. By passing the name of a view and optionally some positional or
keyword arguments; the URL will be reverse resolved using the keyword arguments; the URL will be reverse resolved using the
:func:`~django.core.urlresolvers.reverse` method:: :func:`~django.urls.reverse` method::
def my_view(request): def my_view(request):
... ...

View File

@ -533,8 +533,7 @@ layers where URLs are needed:
* In templates: Using the :ttag:`url` template tag. * In templates: Using the :ttag:`url` template tag.
* In Python code: Using the :func:`django.core.urlresolvers.reverse` * In Python code: Using the :func:`~django.urls.reverse` function.
function.
* In higher level code related to handling of URLs of Django model instances: * In higher level code related to handling of URLs of Django model instances:
The :meth:`~django.db.models.Model.get_absolute_url` method. The :meth:`~django.db.models.Model.get_absolute_url` method.
@ -571,7 +570,7 @@ You can obtain these in template code by using:
Or in Python code:: Or in Python code::
from django.core.urlresolvers import reverse from django.urls import reverse
from django.http import HttpResponseRedirect from django.http import HttpResponseRedirect
def redirect_to_year(request): def redirect_to_year(request):
@ -671,8 +670,8 @@ the fully qualified name into parts and then tries the following lookup:
2. If there is a current application defined, Django finds and returns the URL 2. If there is a current application defined, Django finds and returns the URL
resolver for that instance. The current application can be specified with resolver for that instance. The current application can be specified with
the ``current_app`` argument to the the ``current_app`` argument to the :func:`~django.urls.reverse()`
:func:`~django.core.urlresolvers.reverse()` function. function.
The :ttag:`url` template tag uses the namespace of the currently resolved The :ttag:`url` template tag uses the namespace of the currently resolved
view as the current application in a view as the current application in a

View File

@ -1360,7 +1360,7 @@ 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::
from django.core.urlresolvers import reverse from django.urls import reverse
from django.utils.translation import activate from django.utils.translation import activate
>>> activate('en') >>> activate('en')
@ -1414,11 +1414,10 @@ URL patterns can also be marked translatable using the
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.urls.reverse`
:func:`~django.core.urlresolvers.reverse` function will return the URL in the function will return the URL in the active language. Example::
active language. Example::
from django.core.urlresolvers import reverse from django.urls import reverse
from django.utils.translation import activate from django.utils.translation import activate
>>> activate('en') >>> activate('en')

View File

@ -411,7 +411,7 @@ For example, you can create ``myproject/jinja2.py`` with this content::
from __future__ import absolute_import # Python 2 only from __future__ import absolute_import # Python 2 only
from django.contrib.staticfiles.storage import staticfiles_storage from django.contrib.staticfiles.storage import staticfiles_storage
from django.core.urlresolvers import reverse from django.urls import reverse
from jinja2 import Environment from jinja2 import Environment

View File

@ -507,9 +507,8 @@ Specifically, a ``Response`` object has the following attributes:
.. attribute:: resolver_match .. attribute:: resolver_match
An instance of :class:`~django.core.urlresolvers.ResolverMatch` for the An instance of :class:`~django.urls.ResolverMatch` for the response.
response. You can use the You can use the :attr:`~django.urls.ResolverMatch.func` attribute, for
:attr:`~django.core.urlresolvers.ResolverMatch.func` attribute, for
example, to verify the view that served the response:: example, to verify the view that served the response::
# my_view here is a function based view # my_view here is a function based view
@ -520,7 +519,7 @@ Specifically, a ``Response`` object has the following attributes:
self.assertEqual(response.resolver_match.func.__name__, MyView.as_view().__name__) self.assertEqual(response.resolver_match.func.__name__, MyView.as_view().__name__)
If the given URL is not found, accessing this attribute will raise a If the given URL is not found, accessing this attribute will raise a
:exc:`~django.core.urlresolvers.Resolver404` exception. :exc:`~django.urls.Resolver404` exception.
You can also use dictionary syntax on the response object to query the value You can also use dictionary syntax on the response object to query the value
of any settings in the HTTP headers. For example, you could determine the of any settings in the HTTP headers. For example, you could determine the

View File

@ -10,10 +10,10 @@ from django.contrib.admin.tests import AdminSeleniumWebDriverTestCase
from django.contrib.admin.views.main import ALL_VAR, SEARCH_VAR, ChangeList from django.contrib.admin.views.main import ALL_VAR, SEARCH_VAR, ChangeList
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.core.urlresolvers import reverse
from django.template import Context, Template from django.template import Context, Template
from django.test import TestCase, ignore_warnings, override_settings from django.test import TestCase, ignore_warnings, override_settings
from django.test.client import RequestFactory from django.test.client import RequestFactory
from django.urls import reverse
from django.utils import formats, six from django.utils import formats, six
from django.utils.deprecation import RemovedInDjango20Warning from django.utils.deprecation import RemovedInDjango20Warning

View File

@ -1,9 +1,9 @@
from functools import update_wrapper from functools import update_wrapper
from django.contrib import admin from django.contrib import admin
from django.core.urlresolvers import reverse
from django.db import models from django.db import models
from django.http import HttpResponseRedirect from django.http import HttpResponseRedirect
from django.urls import reverse
from django.utils.encoding import python_2_unicode_compatible from django.utils.encoding import python_2_unicode_compatible

View File

@ -4,9 +4,9 @@ import datetime
from django.contrib.admin.utils import quote from django.contrib.admin.utils import quote
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.core.urlresolvers import reverse
from django.template.response import TemplateResponse from django.template.response import TemplateResponse
from django.test import TestCase, override_settings from django.test import TestCase, override_settings
from django.urls import reverse
from .models import Action, Car, Person from .models import Action, Car, Person

View File

@ -7,9 +7,9 @@ from django.contrib.admindocs import utils
from django.contrib.admindocs.views import get_return_data_type from django.contrib.admindocs.views import get_return_data_type
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.contrib.sites.models import Site from django.contrib.sites.models import Site
from django.core.urlresolvers import reverse
from django.test import TestCase, modify_settings, override_settings from django.test import TestCase, modify_settings, override_settings
from django.test.utils import captured_stderr from django.test.utils import captured_stderr
from django.urls import reverse
from .models import Company, Person from .models import Company, Person

View File

@ -7,8 +7,8 @@ from django.contrib.admin.helpers import InlineAdminForm
from django.contrib.admin.tests import AdminSeleniumWebDriverTestCase from django.contrib.admin.tests import AdminSeleniumWebDriverTestCase
from django.contrib.auth.models import Permission, User from django.contrib.auth.models import Permission, User
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.core.urlresolvers import reverse
from django.test import RequestFactory, TestCase, override_settings from django.test import RequestFactory, TestCase, override_settings
from django.urls import reverse
from .admin import InnerInline, site as admin_site from .admin import InnerInline, site as admin_site
from .models import ( from .models import (

View File

@ -6,8 +6,8 @@ from django.contrib.admin.models import ADDITION, CHANGE, DELETION, LogEntry
from django.contrib.admin.utils import quote from django.contrib.admin.utils import quote
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.core.urlresolvers import reverse
from django.test import TestCase, override_settings from django.test import TestCase, override_settings
from django.urls import reverse
from django.utils import six from django.utils import six
from django.utils.encoding import force_bytes from django.utils.encoding import force_bytes
from django.utils.html import escape from django.utils.html import escape

View File

@ -5,9 +5,9 @@ import datetime
from django.conf.urls import url from django.conf.urls import url
from django.contrib import admin from django.contrib import admin
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.core.urlresolvers import reverse
from django.test import TestCase, override_settings from django.test import TestCase, override_settings
from django.test.client import RequestFactory from django.test.client import RequestFactory
from django.urls import reverse
from .models import Article from .models import Article

View File

@ -23,7 +23,6 @@ from django.contrib.staticfiles.storage import staticfiles_storage
from django.core import mail from django.core import mail
from django.core.checks import Error from django.core.checks import Error
from django.core.files import temp as tempfile from django.core.files import temp as tempfile
from django.core.urlresolvers import NoReverseMatch, resolve, reverse
from django.forms.utils import ErrorList from django.forms.utils import ErrorList
from django.template.loader import render_to_string from django.template.loader import render_to_string
from django.template.response import TemplateResponse from django.template.response import TemplateResponse
@ -32,6 +31,7 @@ from django.test import (
override_settings, skipUnlessDBFeature, override_settings, skipUnlessDBFeature,
) )
from django.test.utils import override_script_prefix, patch_logger from django.test.utils import override_script_prefix, patch_logger
from django.urls import NoReverseMatch, resolve, reverse
from django.utils import formats, six, translation from django.utils import formats, six, translation
from django.utils._os import upath from django.utils._os import upath
from django.utils.cache import get_max_age from django.utils.cache import get_max_age

View File

@ -15,9 +15,9 @@ from django.contrib.admin.tests import AdminSeleniumWebDriverTestCase
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.core.files.storage import default_storage from django.core.files.storage import default_storage
from django.core.files.uploadedfile import SimpleUploadedFile from django.core.files.uploadedfile import SimpleUploadedFile
from django.core.urlresolvers import reverse
from django.db.models import CharField, DateField from django.db.models import CharField, DateField
from django.test import SimpleTestCase, TestCase, override_settings from django.test import SimpleTestCase, TestCase, override_settings
from django.urls import reverse
from django.utils import six, translation from django.utils import six, translation
from . import models from . import models

View File

@ -20,12 +20,12 @@ from django.contrib.auth.views import login as login_view, redirect_to_login
from django.contrib.sessions.middleware import SessionMiddleware from django.contrib.sessions.middleware import SessionMiddleware
from django.contrib.sites.requests import RequestSite from django.contrib.sites.requests import RequestSite
from django.core import mail from django.core import mail
from django.core.urlresolvers import NoReverseMatch, reverse, reverse_lazy
from django.db import connection from django.db import connection
from django.http import HttpRequest, QueryDict from django.http import HttpRequest, QueryDict
from django.middleware.csrf import CsrfViewMiddleware, get_token from django.middleware.csrf import CsrfViewMiddleware, get_token
from django.test import TestCase, override_settings from django.test import TestCase, override_settings
from django.test.utils import patch_logger from django.test.utils import patch_logger
from django.urls import NoReverseMatch, reverse, reverse_lazy
from django.utils.encoding import force_text from django.utils.encoding import force_text
from django.utils.http import urlquote from django.utils.http import urlquote
from django.utils.six.moves.urllib.parse import ParseResult, urlparse from django.utils.six.moves.urllib.parse import ParseResult, urlparse

View File

@ -2,7 +2,6 @@
from __future__ import unicode_literals from __future__ import unicode_literals
from django.contrib.admin.tests import AdminSeleniumWebDriverTestCase from django.contrib.admin.tests import AdminSeleniumWebDriverTestCase
from django.core.urlresolvers import reverse
from django.forms import ( from django.forms import (
CheckboxSelectMultiple, ClearableFileInput, RadioSelect, TextInput, CheckboxSelectMultiple, ClearableFileInput, RadioSelect, TextInput,
) )
@ -10,6 +9,7 @@ from django.forms.widgets import (
ChoiceFieldRenderer, ChoiceInput, RadioFieldRenderer, ChoiceFieldRenderer, ChoiceInput, RadioFieldRenderer,
) )
from django.test import SimpleTestCase, override_settings from django.test import SimpleTestCase, override_settings
from django.urls import reverse
from django.utils import six from django.utils import six
from django.utils.encoding import force_text, python_2_unicode_compatible from django.utils.encoding import force_text, python_2_unicode_compatible
from django.utils.safestring import SafeData from django.utils.safestring import SafeData

View File

@ -9,12 +9,12 @@ from django.contrib.auth.models import User
from django.contrib.contenttypes.admin import GenericTabularInline from django.contrib.contenttypes.admin import GenericTabularInline
from django.contrib.contenttypes.forms import generic_inlineformset_factory from django.contrib.contenttypes.forms import generic_inlineformset_factory
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.core.urlresolvers import reverse
from django.forms.formsets import DEFAULT_MAX_NUM from django.forms.formsets import DEFAULT_MAX_NUM
from django.forms.models import ModelForm from django.forms.models import ModelForm
from django.test import ( from django.test import (
RequestFactory, SimpleTestCase, TestCase, override_settings, RequestFactory, SimpleTestCase, TestCase, override_settings,
) )
from django.urls import reverse
from .admin import MediaInline, MediaPermanentInline, site as admin_site from .admin import MediaInline, MediaPermanentInline, site as admin_site
from .models import Category, Episode, EpisodePermanent, Media, PhoneNumber from .models import Category, Episode, EpisodePermanent, Media, PhoneNumber

View File

@ -1,7 +1,7 @@
from django.core.urlresolvers import reverse
from django.db import models from django.db import models
from django.db.models import QuerySet from django.db.models import QuerySet
from django.db.models.manager import BaseManager from django.db.models.manager import BaseManager
from django.urls import reverse
from django.utils.encoding import python_2_unicode_compatible from django.utils.encoding import python_2_unicode_compatible

View File

@ -4,10 +4,10 @@ import time
import unittest import unittest
from django.core.exceptions import ImproperlyConfigured from django.core.exceptions import ImproperlyConfigured
from django.core.urlresolvers import resolve
from django.http import HttpResponse from django.http import HttpResponse
from django.test import RequestFactory, SimpleTestCase, override_settings from django.test import RequestFactory, SimpleTestCase, override_settings
from django.test.utils import require_jinja2 from django.test.utils import require_jinja2
from django.urls import resolve
from django.views.generic import RedirectView, TemplateView, View from django.views.generic import RedirectView, TemplateView, View
from . import views from . import views

View File

@ -2,9 +2,9 @@ from __future__ import unicode_literals
from django import forms from django import forms
from django.core.exceptions import ImproperlyConfigured from django.core.exceptions import ImproperlyConfigured
from django.core.urlresolvers import reverse
from django.test import SimpleTestCase, TestCase, override_settings from django.test import SimpleTestCase, TestCase, override_settings
from django.test.client import RequestFactory from django.test.client import RequestFactory
from django.urls import reverse
from django.views.generic.base import View from django.views.generic.base import View
from django.views.generic.edit import CreateView, FormMixin, ModelFormMixin from django.views.generic.edit import CreateView, FormMixin, ModelFormMixin

View File

@ -2,7 +2,7 @@ from __future__ import unicode_literals
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
from django.core.paginator import Paginator from django.core.paginator import Paginator
from django.core.urlresolvers import reverse, reverse_lazy from django.urls import reverse, reverse_lazy
from django.utils.decorators import method_decorator from django.utils.decorators import method_decorator
from django.views import generic from django.views import generic

View File

@ -3,12 +3,12 @@ from __future__ import unicode_literals
import os import os
from django.core.exceptions import ImproperlyConfigured from django.core.exceptions import ImproperlyConfigured
from django.core.urlresolvers import clear_url_caches, reverse, translate_url
from django.http import HttpResponsePermanentRedirect from django.http import HttpResponsePermanentRedirect
from django.middleware.locale import LocaleMiddleware from django.middleware.locale import LocaleMiddleware
from django.template import Context, Template from django.template import Context, Template
from django.test import SimpleTestCase, override_settings from django.test import SimpleTestCase, override_settings
from django.test.utils import override_script_prefix from django.test.utils import override_script_prefix
from django.urls import clear_url_caches, reverse, translate_url
from django.utils import translation from django.utils import translation
from django.utils._os import upath from django.utils._os import upath

View File

@ -4,8 +4,8 @@ from django.contrib.messages.api import MessageFailure
from django.contrib.messages.constants import DEFAULT_LEVELS from django.contrib.messages.constants import DEFAULT_LEVELS
from django.contrib.messages.storage import base, default_storage from django.contrib.messages.storage import base, default_storage
from django.contrib.messages.storage.base import Message from django.contrib.messages.storage.base import Message
from django.core.urlresolvers import reverse
from django.test import modify_settings, override_settings from django.test import modify_settings, override_settings
from django.urls import reverse
from django.utils.translation import ugettext_lazy from django.utils.translation import ugettext_lazy

View File

@ -1,5 +1,5 @@
from django.core.urlresolvers import reverse
from django.test import SimpleTestCase, override_settings from django.test import SimpleTestCase, override_settings
from django.urls import reverse
from .urls import ContactFormViewWithMsg from .urls import ContactFormViewWithMsg

View File

@ -2,10 +2,10 @@ from django import forms
from django.conf.urls import url from django.conf.urls import url
from django.contrib import messages from django.contrib import messages
from django.contrib.messages.views import SuccessMessageMixin from django.contrib.messages.views import SuccessMessageMixin
from django.core.urlresolvers import reverse
from django.http import HttpResponse, HttpResponseRedirect from django.http import HttpResponse, HttpResponseRedirect
from django.template import engines from django.template import engines
from django.template.response import TemplateResponse from django.template.response import TemplateResponse
from django.urls import reverse
from django.views.decorators.cache import never_cache from django.views.decorators.cache import never_cache
from django.views.generic.edit import FormView from django.views.generic.edit import FormView

Some files were not shown because too many files have changed in this diff Show More