mirror of
https://github.com/django/django.git
synced 2024-12-22 09:05:43 +00:00
Fixed #26013 -- Moved django.core.urlresolvers to django.urls.
Thanks to Tim Graham for the review.
This commit is contained in:
parent
df3d5b1d73
commit
16411b8400
@ -15,7 +15,7 @@ def setup(set_prefix=True):
|
||||
"""
|
||||
from django.apps import apps
|
||||
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.log import configure_logging
|
||||
|
||||
|
@ -2,7 +2,7 @@ import warnings
|
||||
from importlib import import_module
|
||||
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
from django.core.urlresolvers import (
|
||||
from django.urls import (
|
||||
LocaleRegexURLResolver, RegexURLPattern, RegexURLResolver,
|
||||
)
|
||||
from django.utils import six
|
||||
|
@ -1,6 +1,6 @@
|
||||
from django.conf import settings
|
||||
from django.conf.urls import url
|
||||
from django.core.urlresolvers import LocaleRegexURLResolver
|
||||
from django.urls import LocaleRegexURLResolver
|
||||
from django.views.i18n import set_language
|
||||
|
||||
|
||||
|
@ -3,8 +3,8 @@ from __future__ import unicode_literals
|
||||
from django.conf import settings
|
||||
from django.contrib.admin.utils import quote
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.core.urlresolvers import NoReverseMatch, reverse
|
||||
from django.db import models
|
||||
from django.urls import NoReverseMatch, reverse
|
||||
from django.utils import timezone
|
||||
from django.utils.encoding import python_2_unicode_compatible, smart_text
|
||||
from django.utils.translation import ugettext, ugettext_lazy as _
|
||||
|
@ -24,7 +24,6 @@ from django.core.exceptions import (
|
||||
FieldDoesNotExist, FieldError, PermissionDenied, ValidationError,
|
||||
)
|
||||
from django.core.paginator import Paginator
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.db import models, router, transaction
|
||||
from django.db.models.constants import LOOKUP_SEP
|
||||
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.response import HttpResponseBase
|
||||
from django.template.response import SimpleTemplateResponse, TemplateResponse
|
||||
from django.urls import reverse
|
||||
from django.utils import six
|
||||
from django.utils.decorators import method_decorator
|
||||
from django.utils.encoding import force_text, python_2_unicode_compatible
|
||||
|
@ -5,11 +5,11 @@ from django.conf import settings
|
||||
from django.contrib.admin import ModelAdmin, actions
|
||||
from django.contrib.auth import REDIRECT_FIELD_NAME
|
||||
from django.core.exceptions import ImproperlyConfigured, PermissionDenied
|
||||
from django.core.urlresolvers import NoReverseMatch, reverse
|
||||
from django.db.models.base import ModelBase
|
||||
from django.http import Http404, HttpResponseRedirect
|
||||
from django.template.engine import Engine
|
||||
from django.template.response import TemplateResponse
|
||||
from django.urls import NoReverseMatch, reverse
|
||||
from django.utils import six
|
||||
from django.utils.text import capfirst
|
||||
from django.utils.translation import ugettext as _, ugettext_lazy
|
||||
|
@ -11,11 +11,11 @@ from django.contrib.admin.views.main import (
|
||||
ALL_VAR, ORDER_VAR, PAGE_VAR, SEARCH_VAR,
|
||||
)
|
||||
from django.core.exceptions import ObjectDoesNotExist
|
||||
from django.core.urlresolvers import NoReverseMatch
|
||||
from django.db import models
|
||||
from django.template import Library
|
||||
from django.template.loader import get_template
|
||||
from django.templatetags.static import static
|
||||
from django.urls import NoReverseMatch
|
||||
from django.utils import formats
|
||||
from django.utils.deprecation import RemovedInDjango20Warning
|
||||
from django.utils.encoding import force_text
|
||||
|
@ -1,6 +1,6 @@
|
||||
from django import template
|
||||
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.six.moves.urllib.parse import parse_qsl, urlparse, urlunparse
|
||||
|
||||
|
@ -6,12 +6,12 @@ from collections import defaultdict
|
||||
|
||||
from django.contrib.auth import get_permission_codename
|
||||
from django.core.exceptions import FieldDoesNotExist
|
||||
from django.core.urlresolvers import NoReverseMatch, reverse
|
||||
from django.db import models
|
||||
from django.db.models.constants import LOOKUP_SEP
|
||||
from django.db.models.deletion import Collector
|
||||
from django.db.models.sql.constants import QUERY_TERMS
|
||||
from django.forms.utils import pretty_name
|
||||
from django.urls import NoReverseMatch, reverse
|
||||
from django.utils import formats, six, timezone
|
||||
from django.utils.encoding import force_str, force_text, smart_text
|
||||
from django.utils.html import format_html
|
||||
|
@ -15,8 +15,8 @@ from django.core.exceptions import (
|
||||
FieldDoesNotExist, ImproperlyConfigured, SuspiciousOperation,
|
||||
)
|
||||
from django.core.paginator import InvalidPage
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.db import models
|
||||
from django.urls import reverse
|
||||
from django.utils import six
|
||||
from django.utils.encoding import force_text
|
||||
from django.utils.http import urlencode
|
||||
|
@ -6,11 +6,11 @@ from __future__ import unicode_literals
|
||||
import copy
|
||||
|
||||
from django import forms
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.db.models.deletion import CASCADE
|
||||
from django.forms.utils import flatatt
|
||||
from django.forms.widgets import RadioFieldRenderer
|
||||
from django.template.loader import render_to_string
|
||||
from django.urls import reverse
|
||||
from django.utils import six
|
||||
from django.utils.encoding import force_text
|
||||
from django.utils.html import (
|
||||
|
@ -4,7 +4,7 @@ import re
|
||||
from email.errors import HeaderParseError
|
||||
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.safestring import mark_safe
|
||||
|
||||
|
@ -8,11 +8,11 @@ from django.conf import settings
|
||||
from django.contrib import admin
|
||||
from django.contrib.admin.views.decorators import staff_member_required
|
||||
from django.contrib.admindocs import utils
|
||||
from django.core import urlresolvers
|
||||
from django.core.exceptions import ImproperlyConfigured, ViewDoesNotExist
|
||||
from django.db import models
|
||||
from django.http import Http404
|
||||
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.inspect import (
|
||||
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)
|
||||
|
||||
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))
|
||||
return super(BaseAdminDocsView, self).get_context_data(**kwargs)
|
||||
|
||||
@ -147,9 +147,9 @@ class ViewDetailView(BaseAdminDocsView):
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
view = self.kwargs['view']
|
||||
urlconf = urlresolvers.get_urlconf()
|
||||
if urlresolvers.get_resolver(urlconf)._is_callback(view):
|
||||
mod, func = urlresolvers.get_mod_func(view)
|
||||
urlconf = get_urlconf()
|
||||
if get_resolver(urlconf)._is_callback(view):
|
||||
mod, func = get_mod_func(view)
|
||||
view_func = getattr(import_module(mod), func)
|
||||
else:
|
||||
raise Http404
|
||||
|
@ -9,10 +9,10 @@ from django.contrib.auth.forms import (
|
||||
)
|
||||
from django.contrib.auth.models import Group, User
|
||||
from django.core.exceptions import PermissionDenied
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.db import transaction
|
||||
from django.http import Http404, HttpResponseRedirect
|
||||
from django.template.response import TemplateResponse
|
||||
from django.urls import reverse
|
||||
from django.utils.decorators import method_decorator
|
||||
from django.utils.encoding import force_text
|
||||
from django.utils.html import escape
|
||||
|
@ -13,10 +13,10 @@ from django.contrib.auth.forms import (
|
||||
)
|
||||
from django.contrib.auth.tokens import default_token_generator
|
||||
from django.contrib.sites.shortcuts import get_current_site
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.http import HttpResponseRedirect, QueryDict
|
||||
from django.shortcuts import resolve_url
|
||||
from django.template.response import TemplateResponse
|
||||
from django.urls import reverse
|
||||
from django.utils.deprecation import RemovedInDjango20Warning
|
||||
from django.utils.encoding import force_text
|
||||
from django.utils.http import is_safe_url, urlsafe_base64_decode
|
||||
|
@ -1,8 +1,8 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.contrib.sites.models import Site
|
||||
from django.core.urlresolvers import get_script_prefix
|
||||
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.translation import ugettext_lazy as _
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
from django.apps import apps
|
||||
from django.contrib.gis.db.models.fields import GeometryField
|
||||
from django.contrib.sitemaps import Sitemap
|
||||
from django.core import urlresolvers
|
||||
from django.db import models
|
||||
from django.urls import reverse
|
||||
|
||||
|
||||
class KMLSitemap(Sitemap):
|
||||
@ -56,12 +56,14 @@ class KMLSitemap(Sitemap):
|
||||
return self.locations
|
||||
|
||||
def location(self, obj):
|
||||
return urlresolvers.reverse('django.contrib.gis.sitemaps.views.%s' % self.geo_format,
|
||||
kwargs={'label': obj[0],
|
||||
'model': obj[1],
|
||||
'field_name': obj[2],
|
||||
}
|
||||
)
|
||||
return reverse(
|
||||
'django.contrib.gis.sitemaps.views.%s' % self.geo_format,
|
||||
kwargs={
|
||||
'label': obj[0],
|
||||
'model': obj[1],
|
||||
'field_name': obj[2],
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
class KMZSitemap(KMLSitemap):
|
||||
|
@ -1,7 +1,8 @@
|
||||
from django.apps import apps as django_apps
|
||||
from django.conf import settings
|
||||
from django.core import paginator, urlresolvers
|
||||
from django.core import paginator
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
from django.urls import NoReverseMatch, reverse
|
||||
from django.utils import translation
|
||||
from django.utils.six.moves.urllib.parse import urlencode
|
||||
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.
|
||||
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
|
||||
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:
|
||||
try:
|
||||
# First, try to get the "index" sitemap URL.
|
||||
sitemap_url = urlresolvers.reverse('django.contrib.sitemaps.views.index')
|
||||
except urlresolvers.NoReverseMatch:
|
||||
sitemap_url = reverse('django.contrib.sitemaps.views.index')
|
||||
except NoReverseMatch:
|
||||
try:
|
||||
# Next, try for the "global" sitemap URL.
|
||||
sitemap_url = urlresolvers.reverse('django.contrib.sitemaps.views.sitemap')
|
||||
except urlresolvers.NoReverseMatch:
|
||||
sitemap_url = reverse('django.contrib.sitemaps.views.sitemap')
|
||||
except NoReverseMatch:
|
||||
pass
|
||||
|
||||
if sitemap_url is None:
|
||||
|
@ -3,10 +3,10 @@ from calendar import timegm
|
||||
from functools import wraps
|
||||
|
||||
from django.contrib.sites.shortcuts import get_current_site
|
||||
from django.core import urlresolvers
|
||||
from django.core.paginator import EmptyPage, PageNotAnInteger
|
||||
from django.http import Http404
|
||||
from django.template.response import TemplateResponse
|
||||
from django.urls import reverse
|
||||
from django.utils.http import http_date
|
||||
|
||||
|
||||
@ -32,8 +32,7 @@ def index(request, sitemaps,
|
||||
if callable(site):
|
||||
site = site()
|
||||
protocol = req_protocol if site.protocol is None else site.protocol
|
||||
sitemap_url = urlresolvers.reverse(
|
||||
sitemap_url_name, kwargs={'section': section})
|
||||
sitemap_url = reverse(sitemap_url_name, kwargs={'section': section})
|
||||
absolute_url = '%s://%s%s' % (protocol, req_site.domain, sitemap_url)
|
||||
sites.append(absolute_url)
|
||||
for page in range(2, site.paginator.num_pages + 1):
|
||||
|
@ -5,7 +5,7 @@ from . import Tags, Warning, register
|
||||
|
||||
@register(Tags.urls)
|
||||
def check_url_config(app_configs, **kwargs):
|
||||
from django.core.urlresolvers import get_resolver
|
||||
from django.urls import get_resolver
|
||||
resolver = get_resolver()
|
||||
return check_resolver(resolver)
|
||||
|
||||
@ -14,7 +14,7 @@ def check_resolver(resolver):
|
||||
"""
|
||||
Recursively check the resolver.
|
||||
"""
|
||||
from django.core.urlresolvers import RegexURLPattern, RegexURLResolver
|
||||
from django.urls import RegexURLPattern, RegexURLResolver
|
||||
warnings = []
|
||||
for pattern in resolver.url_patterns:
|
||||
if isinstance(pattern, RegexURLResolver):
|
||||
|
@ -7,12 +7,13 @@ import warnings
|
||||
|
||||
from django import http
|
||||
from django.conf import settings
|
||||
from django.core import signals, urlresolvers
|
||||
from django.core import signals
|
||||
from django.core.exceptions import (
|
||||
MiddlewareNotUsed, PermissionDenied, SuspiciousOperation,
|
||||
)
|
||||
from django.db import connections, transaction
|
||||
from django.http.multipartparser import MultiPartParserError
|
||||
from django.urls import get_resolver, set_urlconf
|
||||
from django.utils import six
|
||||
from django.utils.deprecation import RemovedInDjango20Warning
|
||||
from django.utils.encoding import force_text
|
||||
@ -111,8 +112,8 @@ class BaseHandler(object):
|
||||
# variable" exception in the event an exception is raised before
|
||||
# resolver is set
|
||||
urlconf = settings.ROOT_URLCONF
|
||||
urlresolvers.set_urlconf(urlconf)
|
||||
resolver = urlresolvers.get_resolver(urlconf)
|
||||
set_urlconf(urlconf)
|
||||
resolver = get_resolver(urlconf)
|
||||
# Use a flag to check if the response was rendered to prevent
|
||||
# multiple renderings or to force rendering if necessary.
|
||||
response_is_rendered = False
|
||||
@ -128,8 +129,8 @@ class BaseHandler(object):
|
||||
if hasattr(request, 'urlconf'):
|
||||
# Reset url resolver with a custom URLconf.
|
||||
urlconf = request.urlconf
|
||||
urlresolvers.set_urlconf(urlconf)
|
||||
resolver = urlresolvers.get_resolver(urlconf)
|
||||
set_urlconf(urlconf)
|
||||
resolver = get_resolver(urlconf)
|
||||
|
||||
resolver_match = resolver.resolve(request.path_info)
|
||||
callback, callback_args, callback_kwargs = resolver_match
|
||||
|
@ -12,7 +12,7 @@ from django import http
|
||||
from django.conf import settings
|
||||
from django.core import signals
|
||||
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.encoding import force_str, force_text
|
||||
from django.utils.functional import cached_property
|
||||
|
@ -1,640 +1,9 @@
|
||||
"""
|
||||
This module converts requested URLs to callback view functions.
|
||||
import warnings
|
||||
|
||||
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
|
||||
from django.urls import * # NOQA
|
||||
from django.utils.deprecation import RemovedInDjango20Warning
|
||||
|
||||
import functools
|
||||
import re
|
||||
from importlib import import_module
|
||||
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
|
||||
warnings.warn(
|
||||
"Importing from django.core.urlresolvers is deprecated in favor of "
|
||||
"django.urls.", RemovedInDjango20Warning, stacklevel=2
|
||||
)
|
||||
|
@ -26,15 +26,15 @@ from django.db.models.fields.related import ( # NOQA isort:skip
|
||||
|
||||
def permalink(func):
|
||||
"""
|
||||
Decorator that calls urlresolvers.reverse() to return a URL using
|
||||
parameters returned by the decorated function "func".
|
||||
Decorator that calls urls.reverse() to return a URL using parameters
|
||||
returned by the decorated function "func".
|
||||
|
||||
"func" should be a function that returns a tuple in one of the
|
||||
following formats:
|
||||
(viewname, viewargs)
|
||||
(viewname, viewargs, viewkwargs)
|
||||
"""
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.urls import reverse
|
||||
|
||||
@wraps(func)
|
||||
def inner(*args, **kwargs):
|
||||
|
@ -3,9 +3,9 @@ import re
|
||||
|
||||
from django import http
|
||||
from django.conf import settings
|
||||
from django.core import urlresolvers
|
||||
from django.core.exceptions import PermissionDenied
|
||||
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.encoding import force_text
|
||||
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('/'):
|
||||
urlconf = getattr(request, 'urlconf', None)
|
||||
return (
|
||||
not urlresolvers.is_valid_path(request.path_info, urlconf)
|
||||
and urlresolvers.is_valid_path('%s/' % request.path_info, urlconf)
|
||||
not is_valid_path(request.path_info, urlconf)
|
||||
and is_valid_path('%s/' % request.path_info, urlconf)
|
||||
)
|
||||
return False
|
||||
|
||||
|
@ -10,7 +10,7 @@ import logging
|
||||
import re
|
||||
|
||||
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.crypto import constant_time_compare, get_random_string
|
||||
from django.utils.encoding import force_text
|
||||
|
@ -1,10 +1,10 @@
|
||||
"This is the locale selecting middleware that will look at accept headers"
|
||||
|
||||
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,
|
||||
)
|
||||
from django.http import HttpResponseRedirect
|
||||
from django.utils import translation
|
||||
from django.utils.cache import patch_vary_headers
|
||||
from django.utils.functional import cached_property
|
||||
|
@ -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
|
||||
for convenience's sake.
|
||||
"""
|
||||
from django.core import urlresolvers
|
||||
from django.db.models.base import ModelBase
|
||||
from django.db.models.manager import Manager
|
||||
from django.db.models.query import QuerySet
|
||||
@ -11,6 +10,7 @@ from django.http import (
|
||||
Http404, HttpResponse, HttpResponsePermanentRedirect, HttpResponseRedirect,
|
||||
)
|
||||
from django.template import loader
|
||||
from django.urls import NoReverseMatch, reverse
|
||||
from django.utils import six
|
||||
from django.utils.encoding import force_text
|
||||
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 view name, possibly with arguments: `urlresolvers.reverse()` will
|
||||
be used to reverse-resolve the name.
|
||||
* A view name, possibly with arguments: `urls.reverse()` will be used
|
||||
to reverse-resolve the name.
|
||||
|
||||
* 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 view name, possibly with arguments: `urlresolvers.reverse()` will
|
||||
be used to reverse-resolve the name.
|
||||
* A view name, possibly with arguments: `urls.reverse()` will be used
|
||||
to reverse-resolve the name.
|
||||
|
||||
* A URL, which will be returned as-is.
|
||||
"""
|
||||
@ -144,8 +144,8 @@ def resolve_url(to, *args, **kwargs):
|
||||
|
||||
# Next try a reverse URL resolution.
|
||||
try:
|
||||
return urlresolvers.reverse(to, args=args, kwargs=kwargs)
|
||||
except urlresolvers.NoReverseMatch:
|
||||
return reverse(to, args=args, kwargs=kwargs)
|
||||
except NoReverseMatch:
|
||||
# If this is a callable, re-raise.
|
||||
if callable(to):
|
||||
raise
|
||||
|
@ -426,7 +426,7 @@ class URLNode(Node):
|
||||
self.asvar = asvar
|
||||
|
||||
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]
|
||||
kwargs = {
|
||||
smart_text(k, 'ascii'): v.resolve(context)
|
||||
|
@ -11,7 +11,6 @@ from io import BytesIO
|
||||
|
||||
from django.apps import apps
|
||||
from django.conf import settings
|
||||
from django.core import urlresolvers
|
||||
from django.core.handlers.base import BaseHandler
|
||||
from django.core.handlers.wsgi import ISO_8859_1, UTF_8, WSGIRequest
|
||||
from django.core.signals import (
|
||||
@ -22,6 +21,7 @@ from django.http import HttpRequest, QueryDict, SimpleCookie
|
||||
from django.template import TemplateDoesNotExist
|
||||
from django.test import signals
|
||||
from django.test.utils import ContextList
|
||||
from django.urls import resolve
|
||||
from django.utils import six
|
||||
from django.utils.encoding import force_bytes, force_str, uri_to_iri
|
||||
from django.utils.functional import SimpleLazyObject, curry
|
||||
@ -477,8 +477,7 @@ class Client(RequestFactory):
|
||||
response.json = curry(self._parse_json, response)
|
||||
|
||||
# Attach the ResolverMatch instance to the response
|
||||
response.resolver_match = SimpleLazyObject(
|
||||
lambda: urlresolvers.resolve(request['PATH_INFO']))
|
||||
response.resolver_match = SimpleLazyObject(lambda: resolve(request['PATH_INFO']))
|
||||
|
||||
# Flatten a single context. Not really necessary anymore thanks to
|
||||
# the __getattr__ flattening in ContextList, but has some edge-case
|
||||
|
@ -145,7 +145,7 @@ def complex_setting_changed(**kwargs):
|
||||
@receiver(setting_changed)
|
||||
def root_urlconf_changed(**kwargs):
|
||||
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()
|
||||
set_urlconf(None)
|
||||
|
||||
|
@ -12,11 +12,11 @@ from django.apps import apps
|
||||
from django.conf import UserSettingsHolder, settings
|
||||
from django.core import mail
|
||||
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.http import request
|
||||
from django.template import Template
|
||||
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.decorators import ContextDecorator
|
||||
from django.utils.encoding import force_str
|
||||
|
20
django/urls/__init__.py
Normal file
20
django/urls/__init__.py
Normal 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
185
django/urls/base.py
Normal 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
11
django/urls/exceptions.py
Normal 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
393
django/urls/resolvers.py
Normal 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
64
django/urls/utils.py
Normal 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:]
|
@ -5,10 +5,10 @@ import sys
|
||||
import types
|
||||
|
||||
from django.conf import settings
|
||||
from django.core.urlresolvers import Resolver404, resolve
|
||||
from django.http import HttpResponse, HttpResponseNotFound
|
||||
from django.template import Context, Engine, TemplateDoesNotExist
|
||||
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.datastructures import MultiValueDict
|
||||
from django.utils.encoding import force_bytes, smart_text
|
||||
|
@ -5,8 +5,8 @@ from functools import update_wrapper
|
||||
|
||||
from django import http
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
from django.core.urlresolvers import NoReverseMatch, reverse
|
||||
from django.template.response import TemplateResponse
|
||||
from django.urls import NoReverseMatch, reverse
|
||||
from django.utils import six
|
||||
from django.utils.decorators import classonlymethod
|
||||
|
||||
|
@ -6,8 +6,8 @@ import os
|
||||
from django import http
|
||||
from django.apps import apps
|
||||
from django.conf import settings
|
||||
from django.core.urlresolvers import translate_url
|
||||
from django.template import Context, Engine
|
||||
from django.urls import translate_url
|
||||
from django.utils import six
|
||||
from django.utils._os import upath
|
||||
from django.utils.encoding import smart_text
|
||||
|
@ -262,7 +262,7 @@ already been configured).
|
||||
So, if there is a module containing some code as follows::
|
||||
|
||||
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)
|
||||
|
||||
|
@ -128,6 +128,8 @@ details on these changes.
|
||||
|
||||
* The ``shell --plain`` option will be removed.
|
||||
|
||||
* The ``django.core.urlresolvers`` module will be removed.
|
||||
|
||||
.. _deprecation-removed-in-1.10:
|
||||
|
||||
1.10
|
||||
@ -152,8 +154,7 @@ details on these changes.
|
||||
* Using an incorrect count of unpacked values in the ``for`` template tag
|
||||
will raise an exception rather than fail silently.
|
||||
|
||||
* The ability to :func:`~django.core.urlresolvers.reverse` URLs using a dotted
|
||||
Python path will be removed.
|
||||
* The ability to reverse URLs using a dotted Python path will be removed.
|
||||
|
||||
* Support for :py:mod:`optparse` will be dropped for custom management commands
|
||||
(replaced by :py:mod:`argparse`).
|
||||
|
@ -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.
|
||||
|
||||
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
|
||||
==================
|
||||
|
@ -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.http import HttpResponseRedirect, HttpResponse
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.urls import reverse
|
||||
|
||||
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
|
||||
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.
|
||||
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
|
||||
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>`,
|
||||
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/'
|
||||
@ -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.http import HttpResponseRedirect
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.urls import reverse
|
||||
from django.views import generic
|
||||
|
||||
from .models import Choice, Question
|
||||
|
@ -362,7 +362,7 @@ With that ready, we can ask the client to do some work for us::
|
||||
404
|
||||
>>> # on the other hand we should expect to find something at '/polls/'
|
||||
>>> # 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.status_code
|
||||
200
|
||||
@ -447,7 +447,7 @@ Add the following to ``polls/tests.py``:
|
||||
.. snippet::
|
||||
: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
|
||||
class:
|
||||
|
@ -13,7 +13,7 @@ views for displaying drilldown pages for date-based data.
|
||||
defined as follows in ``myapp/models.py``::
|
||||
|
||||
from django.db import models
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.urls import reverse
|
||||
|
||||
class Article(models.Model):
|
||||
title = models.CharField(max_length=200)
|
||||
|
@ -15,7 +15,7 @@ editing content:
|
||||
Some of the examples on this page assume that an ``Author`` model has been
|
||||
defined as follows in ``myapp/models.py``::
|
||||
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.urls import reverse
|
||||
from django.db import models
|
||||
|
||||
class Author(models.Model):
|
||||
@ -227,7 +227,7 @@ DeleteView
|
||||
**Example myapp/views.py**::
|
||||
|
||||
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
|
||||
|
||||
class AuthorDelete(DeleteView):
|
||||
|
@ -1252,7 +1252,7 @@ subclass::
|
||||
For example::
|
||||
|
||||
from django.contrib import admin
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.urls import reverse
|
||||
|
||||
class PersonAdmin(admin.ModelAdmin):
|
||||
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
|
||||
call::
|
||||
|
||||
>>> from django.core import urlresolvers
|
||||
>>> from django.urls import reverse
|
||||
>>> 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
|
||||
(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
|
||||
``custom``, you would need to call::
|
||||
|
||||
>>> change_url = urlresolvers.reverse('admin:polls_choice_change',
|
||||
... args=(c.id,), current_app='custom')
|
||||
>>> change_url = reverse('admin:polls_choice_change', args=(c.id,), current_app='custom')
|
||||
|
||||
For more details, see the documentation on :ref:`reversing namespaced URLs
|
||||
<topics-http-reversing-url-namespaces>`.
|
||||
|
@ -300,13 +300,12 @@ Sitemap for static views
|
||||
|
||||
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
|
||||
names for these views in ``items`` and call
|
||||
:func:`~django.core.urlresolvers.reverse` in the ``location`` method of
|
||||
the sitemap. For example::
|
||||
names for these views in ``items`` and call :func:`~django.urls.reverse` in
|
||||
the ``location`` method of the sitemap. For example::
|
||||
|
||||
# sitemaps.py
|
||||
from django.contrib import sitemaps
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.urls import reverse
|
||||
|
||||
class StaticViewSitemap(sitemaps.Sitemap):
|
||||
priority = 0.5
|
||||
|
@ -53,7 +53,7 @@ This simple example, taken from a hypothetical police beat news site describes
|
||||
a feed of the latest five news items::
|
||||
|
||||
from django.contrib.syndication.views import Feed
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.urls import reverse
|
||||
from policebeat.models import NewsItem
|
||||
|
||||
class LatestEntriesFeed(Feed):
|
||||
|
@ -84,7 +84,7 @@ Django core exception classes are defined in ``django.core.exceptions``.
|
||||
.. exception:: ViewDoesNotExist
|
||||
|
||||
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``
|
||||
---------------------
|
||||
@ -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
|
||||
list of errors.
|
||||
|
||||
.. currentmodule:: django.core.urlresolvers
|
||||
.. currentmodule:: django.urls
|
||||
|
||||
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``
|
||||
---------------
|
||||
@ -155,18 +161,17 @@ URL Resolver exceptions are defined in ``django.core.urlresolvers``.
|
||||
.. exception:: Resolver404
|
||||
|
||||
The :exc:`Resolver404` exception is raised by
|
||||
:func:`django.core.urlresolvers.resolve()` if the path passed to
|
||||
``resolve()`` doesn't map to a view. It's a subclass of
|
||||
:class:`django.http.Http404`.
|
||||
:func:`~django.urls.resolve()` if the path passed to ``resolve()`` doesn't
|
||||
map to a view. It's a subclass of :class:`django.http.Http404`.
|
||||
|
||||
``NoReverseMatch``
|
||||
------------------
|
||||
|
||||
.. exception:: NoReverseMatch
|
||||
|
||||
The :exc:`NoReverseMatch` exception is raised by
|
||||
:mod:`django.core.urlresolvers` when a matching URL in your URLconf
|
||||
cannot be identified based on the parameters supplied.
|
||||
The :exc:`NoReverseMatch` exception is raised by :mod:`django.urls` when a
|
||||
matching URL in your URLconf cannot be identified based on the parameters
|
||||
supplied.
|
||||
|
||||
.. currentmodule:: django.db
|
||||
|
||||
|
@ -672,14 +672,14 @@ For example::
|
||||
def get_absolute_url(self):
|
||||
return "/people/%i/" % self.id
|
||||
|
||||
(Whilst 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`
|
||||
function is usually the best approach.)
|
||||
While this code is correct and simple, it may not be the most portable way to
|
||||
to write this kind of method. The :func:`~django.urls.reverse` function is
|
||||
usually the best approach.
|
||||
|
||||
For example::
|
||||
|
||||
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)])
|
||||
|
||||
One place Django uses ``get_absolute_url()`` is in the admin app. If an object
|
||||
|
@ -160,11 +160,11 @@ All attributes should be considered read-only, unless stated otherwise.
|
||||
|
||||
.. attribute:: HttpRequest.resolver_match
|
||||
|
||||
An instance of :class:`~django.core.urlresolvers.ResolverMatch` representing
|
||||
the 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
|
||||
are executed before url resolving takes place (like ``process_request``, you
|
||||
can use ``process_view`` instead).
|
||||
An instance of :class:`~django.urls.ResolverMatch` representing the
|
||||
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 are executed before URL resolving takes place (like
|
||||
``process_request()``, you can use ``process_view()`` instead).
|
||||
|
||||
Attributes set by application code
|
||||
----------------------------------
|
||||
@ -175,7 +175,7 @@ application.
|
||||
.. attribute:: HttpRequest.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
|
||||
|
||||
|
@ -1024,8 +1024,8 @@ such as this:
|
||||
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
|
||||
:exc:`~django.core.urlresolvers.NoReverseMatch` exception raised, which will
|
||||
cause your site to display an error page.
|
||||
:exc:`~django.urls.NoReverseMatch` exception raised, which will cause your
|
||||
site to display an error page.
|
||||
|
||||
If you'd like to retrieve a URL without displaying it, you can use a slightly
|
||||
different call::
|
||||
|
@ -290,8 +290,8 @@ Taking care in ``get_absolute_url()``
|
||||
|
||||
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
|
||||
way that is suitable for a URL. The :func:`~django.core.urlresolvers.reverse`
|
||||
function handles this for you automatically.
|
||||
way that is suitable for a URL. The :func:`~django.urls.reverse` function
|
||||
handles this for you automatically.
|
||||
|
||||
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,
|
||||
|
@ -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()
|
||||
---------
|
||||
@ -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::
|
||||
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.urls import reverse
|
||||
|
||||
def myview(request):
|
||||
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.
|
||||
|
||||
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
|
||||
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)
|
||||
|
||||
``path`` is the URL path you want to resolve. As with
|
||||
:func:`~django.core.urlresolvers.reverse`, you don't need to
|
||||
worry about the ``urlconf`` parameter. The function returns a
|
||||
:class:`ResolverMatch` object that allows you
|
||||
to access various meta-data about the resolved URL.
|
||||
:func:`~django.urls.reverse`, you don't need to worry about the ``urlconf``
|
||||
parameter. The function returns a :class:`ResolverMatch` object that allows you
|
||||
to access various metadata about the resolved URL.
|
||||
|
||||
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:: ResolverMatch
|
||||
@ -175,10 +180,10 @@ A :class:`ResolverMatch` object can also be assigned to a triple::
|
||||
|
||||
func, args, kwargs = resolve('/some/path/')
|
||||
|
||||
One possible use of :func:`~django.core.urlresolvers.resolve` would be to test
|
||||
whether a view would raise a ``Http404`` error before redirecting to it::
|
||||
One possible use of :func:`~django.urls.resolve` would be to test whether a
|
||||
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.utils.six.moves.urllib.parse import urlparse
|
||||
|
||||
@ -202,12 +207,11 @@ get_script_prefix()
|
||||
|
||||
.. function:: get_script_prefix()
|
||||
|
||||
Normally, you should always use :func:`~django.core.urlresolvers.reverse` to
|
||||
define URLs within your application. However, if your application constructs
|
||||
part of the URL hierarchy itself, you may occasionally need to generate URLs.
|
||||
In that case, you need to be able to find the base URL of the Django project
|
||||
within its Web server (normally, :func:`~django.core.urlresolvers.reverse`
|
||||
takes care of this for you). In that case, you can call
|
||||
``get_script_prefix()``, which will return the script prefix portion of the URL
|
||||
for your Django project. If your Django project is at the root of its web
|
||||
server, this is always ``"/"``.
|
||||
Normally, you should always use :func:`~django.urls.reverse` to define URLs
|
||||
within your application. However, if your application constructs part of the
|
||||
URL hierarchy itself, you may occasionally need to generate URLs. In that
|
||||
case, you need to be able to find the base URL of the Django project within
|
||||
its Web server (normally, :func:`~django.urls.reverse` takes care of this for
|
||||
you). In that case, you can call ``get_script_prefix()``, which will return
|
||||
the script prefix portion of the URL for your Django project. If your Django
|
||||
project is at the root of its web server, this is always ``"/"``.
|
||||
|
@ -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
|
||||
takes place.
|
||||
|
||||
* :func:`~django.core.urlresolvers.reverse` and code which uses it (e.g., the
|
||||
``{% url %}`` template tag) now works with URLs in Django's administrative
|
||||
site, provided that the admin URLs are set up via ``include(admin.site.urls)``
|
||||
(sending admin requests to the ``admin.site.root`` view still works, but URLs
|
||||
in the admin will not be "reversible" when configured this way).
|
||||
* ``reverse()`` and code which uses it (e.g., the ``{% url %}`` template tag)
|
||||
now works with URLs in Django's administrative site, provided that the admin
|
||||
URLs are set up via ``include(admin.site.urls)`` (sending admin requests to
|
||||
the ``admin.site.root`` view still works, but URLs in the admin will not be
|
||||
"reversible" when configured this way).
|
||||
|
||||
* The ``include()`` function in Django URLconf modules can now accept sequences
|
||||
of URL patterns (generated by ``patterns()``) in addition to module names.
|
||||
|
@ -460,6 +460,9 @@ Miscellaneous
|
||||
* The ``shell --plain`` option is deprecated in favor of ``-i python`` or
|
||||
``--interface python``.
|
||||
|
||||
* Importing from the ``django.core.urlresolvers`` module is deprecated in
|
||||
favor of its new location, :mod:`django.urls`.
|
||||
|
||||
.. _removed-features-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
|
||||
raises an exception rather than failing silently.
|
||||
|
||||
* The ability to :func:`~django.core.urlresolvers.reverse` URLs using a dotted
|
||||
Python path is removed.
|
||||
* The ability to :func:`~django.urls.reverse` URLs using a dotted Python path
|
||||
is removed.
|
||||
|
||||
* Support for ``optparse`` is dropped for custom management commands.
|
||||
|
||||
|
@ -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
|
||||
determine the appropriate view to invoke.
|
||||
|
||||
Django also provides a convenience function --
|
||||
:func:`~django.core.urlresolvers.reverse` -- which performs this process
|
||||
in the opposite direction. The ``reverse()`` function takes
|
||||
information about a view and returns a URL which would invoke that
|
||||
view. Use of ``reverse()`` is encouraged for application developers,
|
||||
as the output of ``reverse()`` is always based on the current URL
|
||||
patterns, meaning developers do not need to change other code when
|
||||
making changes to URLs.
|
||||
Django also provides a convenience function -- ``reverse()`` -- which performs
|
||||
this process in the opposite direction. The ``reverse()`` function takes
|
||||
information about a view and returns a URL which would invoke that view. Use
|
||||
of ``reverse()`` is encouraged for application developers, as the output of
|
||||
``reverse()`` is always based on the current URL 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
|
||||
path to the desired view. In this situation, Django will import the
|
||||
|
@ -9,6 +9,5 @@ Django 1.4.12 fixes a regression in the 1.4.11 security release.
|
||||
Bugfixes
|
||||
========
|
||||
|
||||
* Restored the ability to :meth:`~django.core.urlresolvers.reverse` views
|
||||
created using :func:`functools.partial()`
|
||||
(:ticket:`22486`)
|
||||
* Restored the ability to ``reverse()`` views created using
|
||||
:func:`functools.partial()` (:ticket:`22486`).
|
||||
|
@ -6,8 +6,8 @@ Django 1.4.14 release notes
|
||||
|
||||
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
|
||||
starting with two slashes), which could unexpectedly redirect a user to a
|
||||
|
@ -371,8 +371,8 @@ Django 1.4 to store the wizard's state in the user's cookies.
|
||||
``reverse_lazy``
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
A lazily evaluated version of :func:`django.core.urlresolvers.reverse` was
|
||||
added to allow using URL reversals before the project's URLconf gets loaded.
|
||||
A lazily evaluated version of ``reverse()`` was added to allow using URL
|
||||
reversals before the project's URLconf gets loaded.
|
||||
|
||||
Translating URL patterns
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
@ -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
|
||||
determine the appropriate view to invoke.
|
||||
|
||||
Django also provides a convenience function --
|
||||
:func:`~django.core.urlresolvers.reverse` -- which performs this process
|
||||
in the opposite direction. The ``reverse()`` function takes
|
||||
information about a view and returns a URL which would invoke that
|
||||
view. Use of ``reverse()`` is encouraged for application developers,
|
||||
as the output of ``reverse()`` is always based on the current URL
|
||||
patterns, meaning developers do not need to change other code when
|
||||
making changes to URLs.
|
||||
Django also provides a convenience function -- ``reverse()`` -- which performs
|
||||
this process in the opposite direction. The ``reverse()`` function takes
|
||||
information about a view and returns a URL which would invoke that view. Use
|
||||
of ``reverse()`` is encouraged for application developers, as the output of
|
||||
``reverse()`` is always based on the current URL 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
|
||||
path to the desired view. In this situation, Django will import the
|
||||
|
@ -9,5 +9,5 @@ Django 1.5.7 fixes a regression in the 1.5.6 security release.
|
||||
Bugfixes
|
||||
========
|
||||
|
||||
* Restored the ability to :meth:`~django.core.urlresolvers.reverse` views
|
||||
created using :func:`functools.partial()` (:ticket:`22486`).
|
||||
* Restored the ability to ``reverse()`` views created using
|
||||
:func:`functools.partial()` (:ticket:`22486`).
|
||||
|
@ -6,8 +6,8 @@ Django 1.5.9 release notes
|
||||
|
||||
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
|
||||
starting with two slashes), which could unexpectedly redirect a user to a
|
||||
|
@ -293,8 +293,8 @@ Django 1.5 also includes several smaller improvements worth noting:
|
||||
objects fetched into memory. See :meth:`QuerySet.delete()
|
||||
<django.db.models.query.QuerySet.delete>` for details.
|
||||
|
||||
* An instance of :class:`~django.core.urlresolvers.ResolverMatch` is stored on
|
||||
the request as ``resolver_match``.
|
||||
* An instance of ``ResolverMatch`` is stored on the request as
|
||||
``resolver_match``.
|
||||
|
||||
* By default, all logging messages reaching the ``django`` logger when
|
||||
:setting:`DEBUG` is ``True`` are sent to the console (unless you redefine the
|
||||
|
@ -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
|
||||
determine the appropriate view to invoke.
|
||||
|
||||
Django also provides a convenience function --
|
||||
:func:`~django.core.urlresolvers.reverse` -- which performs this process
|
||||
in the opposite direction. The ``reverse()`` function takes
|
||||
information about a view and returns a URL which would invoke that
|
||||
view. Use of ``reverse()`` is encouraged for application developers,
|
||||
as the output of ``reverse()`` is always based on the current URL
|
||||
patterns, meaning developers do not need to change other code when
|
||||
making changes to URLs.
|
||||
Django also provides a convenience function -- ``reverse()`` -- which performs
|
||||
this process in the opposite direction. The ``reverse()`` function takes
|
||||
information about a view and returns a URL which would invoke that view. Use
|
||||
of ``reverse()`` is encouraged for application developers, as the output of
|
||||
``reverse()`` is always based on the current URL 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
|
||||
path to the desired view. In this situation, Django will import the
|
||||
|
@ -13,10 +13,8 @@ Bugfixes
|
||||
cookie format of Django 1.4 and earlier to facilitate upgrading to 1.6 from
|
||||
1.4 (:ticket:`22426`).
|
||||
|
||||
* Restored the ability to :meth:`~django.core.urlresolvers.reverse` views
|
||||
created using :func:`functools.partial()`
|
||||
(:ticket:`22486`).
|
||||
* Restored the ability to ``reverse()`` views created using
|
||||
:func:`functools.partial()` (:ticket:`22486`).
|
||||
|
||||
* Fixed the ``object_id`` of the ``LogEntry`` that's created after a user
|
||||
password change in the admin
|
||||
(:ticket:`22515`).
|
||||
password change in the admin (:ticket:`22515`).
|
||||
|
@ -6,8 +6,8 @@ Django 1.6.6 release notes
|
||||
|
||||
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
|
||||
starting with two slashes), which could unexpectedly redirect a user to a
|
||||
|
@ -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 #}
|
||||
<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`
|
||||
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
|
||||
passing arguments to :func:`~django.core.urlresolvers.reverse`, this may
|
||||
result in double-quoting. If this happens, simply remove the URL quoting from
|
||||
your code. You will also have to replace special characters in URLs used in
|
||||
:func:`~django.test.SimpleTestCase.assertRedirects` with their encoded versions.
|
||||
passing arguments to ``reverse()``, this may result in double-quoting. If this
|
||||
happens, simply remove the URL quoting from your code. You will also have to
|
||||
replace special characters in URLs used in
|
||||
:func:`~django.test.SimpleTestCase.assertRedirects` with their encoded
|
||||
versions.
|
||||
|
||||
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
|
||||
did not allow ``null`` would cause a database exception at runtime.
|
||||
|
||||
* If a :class:`~django.core.urlresolvers.NoReverseMatch` exception is raised
|
||||
from a method when rendering a template, it is not silenced. For example,
|
||||
``{{ obj.view_href }}`` will cause template rendering to fail if
|
||||
``view_href()`` raises ``NoReverseMatch``. There is no change to the
|
||||
:ttag:`{% url %}<url>` tag, it causes template rendering to fail like always
|
||||
when ``NoReverseMatch`` is raised.
|
||||
* If a ``NoReverseMatch`` exception is raised from a method when rendering a
|
||||
template, it is not silenced. For example, ``{{ obj.view_href }}`` will
|
||||
cause template rendering to fail if ``view_href()`` raises
|
||||
``NoReverseMatch``. There is no change to the :ttag:`{% url %}<url>` tag, it
|
||||
causes template rendering to fail like always when ``NoReverseMatch`` is
|
||||
raised.
|
||||
|
||||
* :meth:`django.test.Client.logout` now calls
|
||||
:meth:`django.contrib.auth.logout` which will send the
|
||||
|
@ -82,8 +82,7 @@ Bugfixes
|
||||
(:ticket:`23815`).
|
||||
|
||||
* 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
|
||||
(:ticket:`24097`).
|
||||
passing a ``reverse_lazy()`` result on Python 3 (:ticket:`24097`).
|
||||
|
||||
* Added correct formats for Greek (``el``) (:ticket:`23967`).
|
||||
|
||||
|
@ -1112,9 +1112,8 @@ Miscellaneous
|
||||
* The default max size of the Oracle test tablespace has increased from 300M
|
||||
(or 200M, before 1.7.2) to 500M.
|
||||
|
||||
* :func:`~django.core.urlresolvers.reverse` and
|
||||
:func:`~django.core.urlresolvers.reverse_lazy` now return Unicode strings
|
||||
instead of byte strings.
|
||||
* ``reverse()`` and ``reverse_lazy()`` now return Unicode strings instead of
|
||||
byte strings.
|
||||
|
||||
* The ``CacheClass`` shim has been removed from all cache backends.
|
||||
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
|
||||
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
|
||||
path being reversed to be imported. This behavior has also resulted in a
|
||||
|
@ -1083,12 +1083,10 @@ Miscellaneous
|
||||
:attr:`~django.test.SimpleTestCase.allow_database_queries` class attribute
|
||||
to ``True`` on your test class.
|
||||
|
||||
* :attr:`ResolverMatch.app_name
|
||||
<django.core.urlresolvers.ResolverMatch.app_name>` was changed to contain
|
||||
the full namespace path in the case of nested namespaces. For consistency
|
||||
with :attr:`ResolverMatch.namespace
|
||||
<django.core.urlresolvers.ResolverMatch.namespace>`, the empty value is now
|
||||
an empty string instead of ``None``.
|
||||
* ``ResolverMatch.app_name`` was changed to contain the full namespace path in
|
||||
the case of nested namespaces. For consistency with
|
||||
``ResolverMatch.namespace``, the empty value is now an empty string instead
|
||||
of ``None``.
|
||||
|
||||
* For security hardening, session keys must be at least 8 characters.
|
||||
|
||||
|
@ -98,7 +98,7 @@ First we need to add :meth:`~django.db.models.Model.get_absolute_url()` to our
|
||||
.. snippet::
|
||||
:filename: models.py
|
||||
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.urls import reverse
|
||||
from django.db import models
|
||||
|
||||
class Author(models.Model):
|
||||
@ -115,7 +115,7 @@ here; we don't have to write any logic ourselves:
|
||||
:filename: views.py
|
||||
|
||||
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
|
||||
|
||||
class AuthorCreate(CreateView):
|
||||
@ -131,8 +131,8 @@ here; we don't have to write any logic ourselves:
|
||||
success_url = reverse_lazy('author-list')
|
||||
|
||||
.. note::
|
||||
We have to use :func:`~django.core.urlresolvers.reverse_lazy` here, not
|
||||
just ``reverse`` as the urls are not loaded when the file is imported.
|
||||
We have to use :func:`~django.urls.reverse_lazy` here, not just
|
||||
``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
|
||||
inner ``Meta`` class on :class:`~django.forms.ModelForm`. Unless you define the
|
||||
|
@ -225,7 +225,7 @@ We'll demonstrate this with the ``Author`` model we used in the
|
||||
:filename: views.py
|
||||
|
||||
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.detail import SingleObjectMixin
|
||||
from books.models import Author
|
||||
@ -445,7 +445,7 @@ Our new ``AuthorDetail`` looks like this::
|
||||
|
||||
from django import forms
|
||||
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.edit import FormMixin
|
||||
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 as ``AuthorDisplay`` is using on ``GET``::
|
||||
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.urls import reverse
|
||||
from django.http import HttpResponseForbidden
|
||||
from django.views.generic import FormView
|
||||
from django.views.generic.detail import SingleObjectMixin
|
||||
|
@ -103,9 +103,8 @@ This example is equivalent to::
|
||||
* A model: the model's :meth:`~django.db.models.Model.get_absolute_url()`
|
||||
function will be called.
|
||||
|
||||
* A view name, possibly with arguments: :func:`urlresolvers.reverse
|
||||
<django.core.urlresolvers.reverse>` will be used to reverse-resolve the
|
||||
name.
|
||||
* A view name, possibly with arguments: :func:`~django.urls.reverse` will be
|
||||
used to reverse-resolve the name.
|
||||
|
||||
* An absolute or relative URL, which will be used as-is for the redirect
|
||||
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
|
||||
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):
|
||||
...
|
||||
|
@ -533,8 +533,7 @@ layers where URLs are needed:
|
||||
|
||||
* In templates: Using the :ttag:`url` template tag.
|
||||
|
||||
* In Python code: Using the :func:`django.core.urlresolvers.reverse`
|
||||
function.
|
||||
* In Python code: Using the :func:`~django.urls.reverse` function.
|
||||
|
||||
* In higher level code related to handling of URLs of Django model instances:
|
||||
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::
|
||||
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.urls import reverse
|
||||
from django.http import HttpResponseRedirect
|
||||
|
||||
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
|
||||
resolver for that instance. The current application can be specified with
|
||||
the ``current_app`` argument to the
|
||||
:func:`~django.core.urlresolvers.reverse()` function.
|
||||
the ``current_app`` argument to the :func:`~django.urls.reverse()`
|
||||
function.
|
||||
|
||||
The :ttag:`url` template tag uses the namespace of the currently resolved
|
||||
view as the current application in a
|
||||
|
@ -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``
|
||||
function. Example::
|
||||
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.urls import reverse
|
||||
from django.utils.translation import activate
|
||||
|
||||
>>> activate('en')
|
||||
@ -1414,11 +1414,10 @@ URL patterns can also be marked translatable using the
|
||||
url(_(r'^news/'), include(news_patterns, namespace='news')),
|
||||
)
|
||||
|
||||
After you've created the translations, the
|
||||
:func:`~django.core.urlresolvers.reverse` function will return the URL in the
|
||||
active language. Example::
|
||||
After you've created the translations, the :func:`~django.urls.reverse`
|
||||
function will return the URL in the active language. Example::
|
||||
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.urls import reverse
|
||||
from django.utils.translation import activate
|
||||
|
||||
>>> activate('en')
|
||||
|
@ -411,7 +411,7 @@ For example, you can create ``myproject/jinja2.py`` with this content::
|
||||
from __future__ import absolute_import # Python 2 only
|
||||
|
||||
from django.contrib.staticfiles.storage import staticfiles_storage
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.urls import reverse
|
||||
|
||||
from jinja2 import Environment
|
||||
|
||||
|
@ -507,9 +507,8 @@ Specifically, a ``Response`` object has the following attributes:
|
||||
|
||||
.. attribute:: resolver_match
|
||||
|
||||
An instance of :class:`~django.core.urlresolvers.ResolverMatch` for the
|
||||
response. You can use the
|
||||
:attr:`~django.core.urlresolvers.ResolverMatch.func` attribute, for
|
||||
An instance of :class:`~django.urls.ResolverMatch` for the response.
|
||||
You can use the :attr:`~django.urls.ResolverMatch.func` attribute, for
|
||||
example, to verify the view that served the response::
|
||||
|
||||
# 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__)
|
||||
|
||||
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
|
||||
of any settings in the HTTP headers. For example, you could determine the
|
||||
|
@ -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.auth.models import User
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.template import Context, Template
|
||||
from django.test import TestCase, ignore_warnings, override_settings
|
||||
from django.test.client import RequestFactory
|
||||
from django.urls import reverse
|
||||
from django.utils import formats, six
|
||||
from django.utils.deprecation import RemovedInDjango20Warning
|
||||
|
||||
|
@ -1,9 +1,9 @@
|
||||
from functools import update_wrapper
|
||||
|
||||
from django.contrib import admin
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.db import models
|
||||
from django.http import HttpResponseRedirect
|
||||
from django.urls import reverse
|
||||
from django.utils.encoding import python_2_unicode_compatible
|
||||
|
||||
|
||||
|
@ -4,9 +4,9 @@ import datetime
|
||||
|
||||
from django.contrib.admin.utils import quote
|
||||
from django.contrib.auth.models import User
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.template.response import TemplateResponse
|
||||
from django.test import TestCase, override_settings
|
||||
from django.urls import reverse
|
||||
|
||||
from .models import Action, Car, Person
|
||||
|
||||
|
@ -7,9 +7,9 @@ from django.contrib.admindocs import utils
|
||||
from django.contrib.admindocs.views import get_return_data_type
|
||||
from django.contrib.auth.models import User
|
||||
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.utils import captured_stderr
|
||||
from django.urls import reverse
|
||||
|
||||
from .models import Company, Person
|
||||
|
||||
|
@ -7,8 +7,8 @@ from django.contrib.admin.helpers import InlineAdminForm
|
||||
from django.contrib.admin.tests import AdminSeleniumWebDriverTestCase
|
||||
from django.contrib.auth.models import Permission, User
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.test import RequestFactory, TestCase, override_settings
|
||||
from django.urls import reverse
|
||||
|
||||
from .admin import InnerInline, site as admin_site
|
||||
from .models import (
|
||||
|
@ -6,8 +6,8 @@ from django.contrib.admin.models import ADDITION, CHANGE, DELETION, LogEntry
|
||||
from django.contrib.admin.utils import quote
|
||||
from django.contrib.auth.models import User
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.test import TestCase, override_settings
|
||||
from django.urls import reverse
|
||||
from django.utils import six
|
||||
from django.utils.encoding import force_bytes
|
||||
from django.utils.html import escape
|
||||
|
@ -5,9 +5,9 @@ import datetime
|
||||
from django.conf.urls import url
|
||||
from django.contrib import admin
|
||||
from django.contrib.auth.models import User
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.test import TestCase, override_settings
|
||||
from django.test.client import RequestFactory
|
||||
from django.urls import reverse
|
||||
|
||||
from .models import Article
|
||||
|
||||
|
@ -23,7 +23,6 @@ from django.contrib.staticfiles.storage import staticfiles_storage
|
||||
from django.core import mail
|
||||
from django.core.checks import Error
|
||||
from django.core.files import temp as tempfile
|
||||
from django.core.urlresolvers import NoReverseMatch, resolve, reverse
|
||||
from django.forms.utils import ErrorList
|
||||
from django.template.loader import render_to_string
|
||||
from django.template.response import TemplateResponse
|
||||
@ -32,6 +31,7 @@ from django.test import (
|
||||
override_settings, skipUnlessDBFeature,
|
||||
)
|
||||
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._os import upath
|
||||
from django.utils.cache import get_max_age
|
||||
|
@ -15,9 +15,9 @@ from django.contrib.admin.tests import AdminSeleniumWebDriverTestCase
|
||||
from django.contrib.auth.models import User
|
||||
from django.core.files.storage import default_storage
|
||||
from django.core.files.uploadedfile import SimpleUploadedFile
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.db.models import CharField, DateField
|
||||
from django.test import SimpleTestCase, TestCase, override_settings
|
||||
from django.urls import reverse
|
||||
from django.utils import six, translation
|
||||
|
||||
from . import models
|
||||
|
@ -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.sites.requests import RequestSite
|
||||
from django.core import mail
|
||||
from django.core.urlresolvers import NoReverseMatch, reverse, reverse_lazy
|
||||
from django.db import connection
|
||||
from django.http import HttpRequest, QueryDict
|
||||
from django.middleware.csrf import CsrfViewMiddleware, get_token
|
||||
from django.test import TestCase, override_settings
|
||||
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.http import urlquote
|
||||
from django.utils.six.moves.urllib.parse import ParseResult, urlparse
|
||||
|
@ -2,7 +2,6 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.contrib.admin.tests import AdminSeleniumWebDriverTestCase
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.forms import (
|
||||
CheckboxSelectMultiple, ClearableFileInput, RadioSelect, TextInput,
|
||||
)
|
||||
@ -10,6 +9,7 @@ from django.forms.widgets import (
|
||||
ChoiceFieldRenderer, ChoiceInput, RadioFieldRenderer,
|
||||
)
|
||||
from django.test import SimpleTestCase, override_settings
|
||||
from django.urls import reverse
|
||||
from django.utils import six
|
||||
from django.utils.encoding import force_text, python_2_unicode_compatible
|
||||
from django.utils.safestring import SafeData
|
||||
|
@ -9,12 +9,12 @@ from django.contrib.auth.models import User
|
||||
from django.contrib.contenttypes.admin import GenericTabularInline
|
||||
from django.contrib.contenttypes.forms import generic_inlineformset_factory
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.forms.formsets import DEFAULT_MAX_NUM
|
||||
from django.forms.models import ModelForm
|
||||
from django.test import (
|
||||
RequestFactory, SimpleTestCase, TestCase, override_settings,
|
||||
)
|
||||
from django.urls import reverse
|
||||
|
||||
from .admin import MediaInline, MediaPermanentInline, site as admin_site
|
||||
from .models import Category, Episode, EpisodePermanent, Media, PhoneNumber
|
||||
|
@ -1,7 +1,7 @@
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.db import models
|
||||
from django.db.models import QuerySet
|
||||
from django.db.models.manager import BaseManager
|
||||
from django.urls import reverse
|
||||
from django.utils.encoding import python_2_unicode_compatible
|
||||
|
||||
|
||||
|
@ -4,10 +4,10 @@ import time
|
||||
import unittest
|
||||
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
from django.core.urlresolvers import resolve
|
||||
from django.http import HttpResponse
|
||||
from django.test import RequestFactory, SimpleTestCase, override_settings
|
||||
from django.test.utils import require_jinja2
|
||||
from django.urls import resolve
|
||||
from django.views.generic import RedirectView, TemplateView, View
|
||||
|
||||
from . import views
|
||||
|
@ -2,9 +2,9 @@ from __future__ import unicode_literals
|
||||
|
||||
from django import forms
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.test import SimpleTestCase, TestCase, override_settings
|
||||
from django.test.client import RequestFactory
|
||||
from django.urls import reverse
|
||||
from django.views.generic.base import View
|
||||
from django.views.generic.edit import CreateView, FormMixin, ModelFormMixin
|
||||
|
||||
|
@ -2,7 +2,7 @@ from __future__ import unicode_literals
|
||||
|
||||
from django.contrib.auth.decorators import login_required
|
||||
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.views import generic
|
||||
|
||||
|
@ -3,12 +3,12 @@ from __future__ import unicode_literals
|
||||
import os
|
||||
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
from django.core.urlresolvers import clear_url_caches, reverse, translate_url
|
||||
from django.http import HttpResponsePermanentRedirect
|
||||
from django.middleware.locale import LocaleMiddleware
|
||||
from django.template import Context, Template
|
||||
from django.test import SimpleTestCase, override_settings
|
||||
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._os import upath
|
||||
|
||||
|
@ -4,8 +4,8 @@ from django.contrib.messages.api import MessageFailure
|
||||
from django.contrib.messages.constants import DEFAULT_LEVELS
|
||||
from django.contrib.messages.storage import base, default_storage
|
||||
from django.contrib.messages.storage.base import Message
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.test import modify_settings, override_settings
|
||||
from django.urls import reverse
|
||||
from django.utils.translation import ugettext_lazy
|
||||
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.test import SimpleTestCase, override_settings
|
||||
from django.urls import reverse
|
||||
|
||||
from .urls import ContactFormViewWithMsg
|
||||
|
||||
|
@ -2,10 +2,10 @@ from django import forms
|
||||
from django.conf.urls import url
|
||||
from django.contrib import messages
|
||||
from django.contrib.messages.views import SuccessMessageMixin
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.http import HttpResponse, HttpResponseRedirect
|
||||
from django.template import engines
|
||||
from django.template.response import TemplateResponse
|
||||
from django.urls import reverse
|
||||
from django.views.decorators.cache import never_cache
|
||||
from django.views.generic.edit import FormView
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user