mirror of https://github.com/django/django.git
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.apps import apps
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.urlresolvers import set_script_prefix
|
from django.urls import set_script_prefix
|
||||||
from django.utils.encoding import force_text
|
from django.utils.encoding import force_text
|
||||||
from django.utils.log import configure_logging
|
from django.utils.log import configure_logging
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ import warnings
|
||||||
from importlib import import_module
|
from importlib import import_module
|
||||||
|
|
||||||
from django.core.exceptions import ImproperlyConfigured
|
from django.core.exceptions import ImproperlyConfigured
|
||||||
from django.core.urlresolvers import (
|
from django.urls import (
|
||||||
LocaleRegexURLResolver, RegexURLPattern, RegexURLResolver,
|
LocaleRegexURLResolver, RegexURLPattern, RegexURLResolver,
|
||||||
)
|
)
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.conf.urls import url
|
from django.conf.urls import url
|
||||||
from django.core.urlresolvers import LocaleRegexURLResolver
|
from django.urls import LocaleRegexURLResolver
|
||||||
from django.views.i18n import set_language
|
from django.views.i18n import set_language
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -3,8 +3,8 @@ from __future__ import unicode_literals
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.admin.utils import quote
|
from django.contrib.admin.utils import quote
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from django.core.urlresolvers import NoReverseMatch, reverse
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
from django.urls import NoReverseMatch, reverse
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.utils.encoding import python_2_unicode_compatible, smart_text
|
from django.utils.encoding import python_2_unicode_compatible, smart_text
|
||||||
from django.utils.translation import ugettext, ugettext_lazy as _
|
from django.utils.translation import ugettext, ugettext_lazy as _
|
||||||
|
|
|
@ -24,7 +24,6 @@ from django.core.exceptions import (
|
||||||
FieldDoesNotExist, FieldError, PermissionDenied, ValidationError,
|
FieldDoesNotExist, FieldError, PermissionDenied, ValidationError,
|
||||||
)
|
)
|
||||||
from django.core.paginator import Paginator
|
from django.core.paginator import Paginator
|
||||||
from django.core.urlresolvers import reverse
|
|
||||||
from django.db import models, router, transaction
|
from django.db import models, router, transaction
|
||||||
from django.db.models.constants import LOOKUP_SEP
|
from django.db.models.constants import LOOKUP_SEP
|
||||||
from django.db.models.fields import BLANK_CHOICE_DASH
|
from django.db.models.fields import BLANK_CHOICE_DASH
|
||||||
|
@ -37,6 +36,7 @@ from django.forms.widgets import CheckboxSelectMultiple, SelectMultiple
|
||||||
from django.http import Http404, HttpResponseRedirect
|
from django.http import Http404, HttpResponseRedirect
|
||||||
from django.http.response import HttpResponseBase
|
from django.http.response import HttpResponseBase
|
||||||
from django.template.response import SimpleTemplateResponse, TemplateResponse
|
from django.template.response import SimpleTemplateResponse, TemplateResponse
|
||||||
|
from django.urls import reverse
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
from django.utils.decorators import method_decorator
|
from django.utils.decorators import method_decorator
|
||||||
from django.utils.encoding import force_text, python_2_unicode_compatible
|
from django.utils.encoding import force_text, python_2_unicode_compatible
|
||||||
|
|
|
@ -5,11 +5,11 @@ from django.conf import settings
|
||||||
from django.contrib.admin import ModelAdmin, actions
|
from django.contrib.admin import ModelAdmin, actions
|
||||||
from django.contrib.auth import REDIRECT_FIELD_NAME
|
from django.contrib.auth import REDIRECT_FIELD_NAME
|
||||||
from django.core.exceptions import ImproperlyConfigured, PermissionDenied
|
from django.core.exceptions import ImproperlyConfigured, PermissionDenied
|
||||||
from django.core.urlresolvers import NoReverseMatch, reverse
|
|
||||||
from django.db.models.base import ModelBase
|
from django.db.models.base import ModelBase
|
||||||
from django.http import Http404, HttpResponseRedirect
|
from django.http import Http404, HttpResponseRedirect
|
||||||
from django.template.engine import Engine
|
from django.template.engine import Engine
|
||||||
from django.template.response import TemplateResponse
|
from django.template.response import TemplateResponse
|
||||||
|
from django.urls import NoReverseMatch, reverse
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
from django.utils.text import capfirst
|
from django.utils.text import capfirst
|
||||||
from django.utils.translation import ugettext as _, ugettext_lazy
|
from django.utils.translation import ugettext as _, ugettext_lazy
|
||||||
|
|
|
@ -11,11 +11,11 @@ from django.contrib.admin.views.main import (
|
||||||
ALL_VAR, ORDER_VAR, PAGE_VAR, SEARCH_VAR,
|
ALL_VAR, ORDER_VAR, PAGE_VAR, SEARCH_VAR,
|
||||||
)
|
)
|
||||||
from django.core.exceptions import ObjectDoesNotExist
|
from django.core.exceptions import ObjectDoesNotExist
|
||||||
from django.core.urlresolvers import NoReverseMatch
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.template import Library
|
from django.template import Library
|
||||||
from django.template.loader import get_template
|
from django.template.loader import get_template
|
||||||
from django.templatetags.static import static
|
from django.templatetags.static import static
|
||||||
|
from django.urls import NoReverseMatch
|
||||||
from django.utils import formats
|
from django.utils import formats
|
||||||
from django.utils.deprecation import RemovedInDjango20Warning
|
from django.utils.deprecation import RemovedInDjango20Warning
|
||||||
from django.utils.encoding import force_text
|
from django.utils.encoding import force_text
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
from django import template
|
from django import template
|
||||||
from django.contrib.admin.utils import quote
|
from django.contrib.admin.utils import quote
|
||||||
from django.core.urlresolvers import Resolver404, get_script_prefix, resolve
|
from django.urls import Resolver404, get_script_prefix, resolve
|
||||||
from django.utils.http import urlencode
|
from django.utils.http import urlencode
|
||||||
from django.utils.six.moves.urllib.parse import parse_qsl, urlparse, urlunparse
|
from django.utils.six.moves.urllib.parse import parse_qsl, urlparse, urlunparse
|
||||||
|
|
||||||
|
|
|
@ -6,12 +6,12 @@ from collections import defaultdict
|
||||||
|
|
||||||
from django.contrib.auth import get_permission_codename
|
from django.contrib.auth import get_permission_codename
|
||||||
from django.core.exceptions import FieldDoesNotExist
|
from django.core.exceptions import FieldDoesNotExist
|
||||||
from django.core.urlresolvers import NoReverseMatch, reverse
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.db.models.constants import LOOKUP_SEP
|
from django.db.models.constants import LOOKUP_SEP
|
||||||
from django.db.models.deletion import Collector
|
from django.db.models.deletion import Collector
|
||||||
from django.db.models.sql.constants import QUERY_TERMS
|
from django.db.models.sql.constants import QUERY_TERMS
|
||||||
from django.forms.utils import pretty_name
|
from django.forms.utils import pretty_name
|
||||||
|
from django.urls import NoReverseMatch, reverse
|
||||||
from django.utils import formats, six, timezone
|
from django.utils import formats, six, timezone
|
||||||
from django.utils.encoding import force_str, force_text, smart_text
|
from django.utils.encoding import force_str, force_text, smart_text
|
||||||
from django.utils.html import format_html
|
from django.utils.html import format_html
|
||||||
|
|
|
@ -15,8 +15,8 @@ from django.core.exceptions import (
|
||||||
FieldDoesNotExist, ImproperlyConfigured, SuspiciousOperation,
|
FieldDoesNotExist, ImproperlyConfigured, SuspiciousOperation,
|
||||||
)
|
)
|
||||||
from django.core.paginator import InvalidPage
|
from django.core.paginator import InvalidPage
|
||||||
from django.core.urlresolvers import reverse
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
from django.urls import reverse
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
from django.utils.encoding import force_text
|
from django.utils.encoding import force_text
|
||||||
from django.utils.http import urlencode
|
from django.utils.http import urlencode
|
||||||
|
|
|
@ -6,11 +6,11 @@ from __future__ import unicode_literals
|
||||||
import copy
|
import copy
|
||||||
|
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.core.urlresolvers import reverse
|
|
||||||
from django.db.models.deletion import CASCADE
|
from django.db.models.deletion import CASCADE
|
||||||
from django.forms.utils import flatatt
|
from django.forms.utils import flatatt
|
||||||
from django.forms.widgets import RadioFieldRenderer
|
from django.forms.widgets import RadioFieldRenderer
|
||||||
from django.template.loader import render_to_string
|
from django.template.loader import render_to_string
|
||||||
|
from django.urls import reverse
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
from django.utils.encoding import force_text
|
from django.utils.encoding import force_text
|
||||||
from django.utils.html import (
|
from django.utils.html import (
|
||||||
|
|
|
@ -4,7 +4,7 @@ import re
|
||||||
from email.errors import HeaderParseError
|
from email.errors import HeaderParseError
|
||||||
from email.parser import HeaderParser
|
from email.parser import HeaderParser
|
||||||
|
|
||||||
from django.core.urlresolvers import reverse
|
from django.urls import reverse
|
||||||
from django.utils.encoding import force_bytes
|
from django.utils.encoding import force_bytes
|
||||||
from django.utils.safestring import mark_safe
|
from django.utils.safestring import mark_safe
|
||||||
|
|
||||||
|
|
|
@ -8,11 +8,11 @@ from django.conf import settings
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from django.contrib.admin.views.decorators import staff_member_required
|
from django.contrib.admin.views.decorators import staff_member_required
|
||||||
from django.contrib.admindocs import utils
|
from django.contrib.admindocs import utils
|
||||||
from django.core import urlresolvers
|
|
||||||
from django.core.exceptions import ImproperlyConfigured, ViewDoesNotExist
|
from django.core.exceptions import ImproperlyConfigured, ViewDoesNotExist
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.http import Http404
|
from django.http import Http404
|
||||||
from django.template.engine import Engine
|
from django.template.engine import Engine
|
||||||
|
from django.urls import get_mod_func, get_resolver, get_urlconf, reverse
|
||||||
from django.utils.decorators import method_decorator
|
from django.utils.decorators import method_decorator
|
||||||
from django.utils.inspect import (
|
from django.utils.inspect import (
|
||||||
func_accepts_kwargs, func_accepts_var_args, func_has_no_args,
|
func_accepts_kwargs, func_accepts_var_args, func_has_no_args,
|
||||||
|
@ -38,7 +38,7 @@ class BaseAdminDocsView(TemplateView):
|
||||||
return super(BaseAdminDocsView, self).dispatch(request, *args, **kwargs)
|
return super(BaseAdminDocsView, self).dispatch(request, *args, **kwargs)
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
kwargs.update({'root_path': urlresolvers.reverse('admin:index')})
|
kwargs.update({'root_path': reverse('admin:index')})
|
||||||
kwargs.update(admin.site.each_context(self.request))
|
kwargs.update(admin.site.each_context(self.request))
|
||||||
return super(BaseAdminDocsView, self).get_context_data(**kwargs)
|
return super(BaseAdminDocsView, self).get_context_data(**kwargs)
|
||||||
|
|
||||||
|
@ -147,9 +147,9 @@ class ViewDetailView(BaseAdminDocsView):
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
view = self.kwargs['view']
|
view = self.kwargs['view']
|
||||||
urlconf = urlresolvers.get_urlconf()
|
urlconf = get_urlconf()
|
||||||
if urlresolvers.get_resolver(urlconf)._is_callback(view):
|
if get_resolver(urlconf)._is_callback(view):
|
||||||
mod, func = urlresolvers.get_mod_func(view)
|
mod, func = get_mod_func(view)
|
||||||
view_func = getattr(import_module(mod), func)
|
view_func = getattr(import_module(mod), func)
|
||||||
else:
|
else:
|
||||||
raise Http404
|
raise Http404
|
||||||
|
|
|
@ -9,10 +9,10 @@ from django.contrib.auth.forms import (
|
||||||
)
|
)
|
||||||
from django.contrib.auth.models import Group, User
|
from django.contrib.auth.models import Group, User
|
||||||
from django.core.exceptions import PermissionDenied
|
from django.core.exceptions import PermissionDenied
|
||||||
from django.core.urlresolvers import reverse
|
|
||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
from django.http import Http404, HttpResponseRedirect
|
from django.http import Http404, HttpResponseRedirect
|
||||||
from django.template.response import TemplateResponse
|
from django.template.response import TemplateResponse
|
||||||
|
from django.urls import reverse
|
||||||
from django.utils.decorators import method_decorator
|
from django.utils.decorators import method_decorator
|
||||||
from django.utils.encoding import force_text
|
from django.utils.encoding import force_text
|
||||||
from django.utils.html import escape
|
from django.utils.html import escape
|
||||||
|
|
|
@ -13,10 +13,10 @@ from django.contrib.auth.forms import (
|
||||||
)
|
)
|
||||||
from django.contrib.auth.tokens import default_token_generator
|
from django.contrib.auth.tokens import default_token_generator
|
||||||
from django.contrib.sites.shortcuts import get_current_site
|
from django.contrib.sites.shortcuts import get_current_site
|
||||||
from django.core.urlresolvers import reverse
|
|
||||||
from django.http import HttpResponseRedirect, QueryDict
|
from django.http import HttpResponseRedirect, QueryDict
|
||||||
from django.shortcuts import resolve_url
|
from django.shortcuts import resolve_url
|
||||||
from django.template.response import TemplateResponse
|
from django.template.response import TemplateResponse
|
||||||
|
from django.urls import reverse
|
||||||
from django.utils.deprecation import RemovedInDjango20Warning
|
from django.utils.deprecation import RemovedInDjango20Warning
|
||||||
from django.utils.encoding import force_text
|
from django.utils.encoding import force_text
|
||||||
from django.utils.http import is_safe_url, urlsafe_base64_decode
|
from django.utils.http import is_safe_url, urlsafe_base64_decode
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from django.contrib.sites.models import Site
|
from django.contrib.sites.models import Site
|
||||||
from django.core.urlresolvers import get_script_prefix
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
from django.urls import get_script_prefix
|
||||||
from django.utils.encoding import iri_to_uri, python_2_unicode_compatible
|
from django.utils.encoding import iri_to_uri, python_2_unicode_compatible
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
from django.apps import apps
|
from django.apps import apps
|
||||||
from django.contrib.gis.db.models.fields import GeometryField
|
from django.contrib.gis.db.models.fields import GeometryField
|
||||||
from django.contrib.sitemaps import Sitemap
|
from django.contrib.sitemaps import Sitemap
|
||||||
from django.core import urlresolvers
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
from django.urls import reverse
|
||||||
|
|
||||||
|
|
||||||
class KMLSitemap(Sitemap):
|
class KMLSitemap(Sitemap):
|
||||||
|
@ -56,12 +56,14 @@ class KMLSitemap(Sitemap):
|
||||||
return self.locations
|
return self.locations
|
||||||
|
|
||||||
def location(self, obj):
|
def location(self, obj):
|
||||||
return urlresolvers.reverse('django.contrib.gis.sitemaps.views.%s' % self.geo_format,
|
return reverse(
|
||||||
kwargs={'label': obj[0],
|
'django.contrib.gis.sitemaps.views.%s' % self.geo_format,
|
||||||
'model': obj[1],
|
kwargs={
|
||||||
'field_name': obj[2],
|
'label': obj[0],
|
||||||
}
|
'model': obj[1],
|
||||||
)
|
'field_name': obj[2],
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class KMZSitemap(KMLSitemap):
|
class KMZSitemap(KMLSitemap):
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
from django.apps import apps as django_apps
|
from django.apps import apps as django_apps
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core import paginator, urlresolvers
|
from django.core import paginator
|
||||||
from django.core.exceptions import ImproperlyConfigured
|
from django.core.exceptions import ImproperlyConfigured
|
||||||
|
from django.urls import NoReverseMatch, reverse
|
||||||
from django.utils import translation
|
from django.utils import translation
|
||||||
from django.utils.six.moves.urllib.parse import urlencode
|
from django.utils.six.moves.urllib.parse import urlencode
|
||||||
from django.utils.six.moves.urllib.request import urlopen
|
from django.utils.six.moves.urllib.request import urlopen
|
||||||
|
@ -18,17 +19,17 @@ def ping_google(sitemap_url=None, ping_url=PING_URL):
|
||||||
Alerts Google that the sitemap for the current site has been updated.
|
Alerts Google that the sitemap for the current site has been updated.
|
||||||
If sitemap_url is provided, it should be an absolute path to the sitemap
|
If sitemap_url is provided, it should be an absolute path to the sitemap
|
||||||
for this site -- e.g., '/sitemap.xml'. If sitemap_url is not provided, this
|
for this site -- e.g., '/sitemap.xml'. If sitemap_url is not provided, this
|
||||||
function will attempt to deduce it by using urlresolvers.reverse().
|
function will attempt to deduce it by using urls.reverse().
|
||||||
"""
|
"""
|
||||||
if sitemap_url is None:
|
if sitemap_url is None:
|
||||||
try:
|
try:
|
||||||
# First, try to get the "index" sitemap URL.
|
# First, try to get the "index" sitemap URL.
|
||||||
sitemap_url = urlresolvers.reverse('django.contrib.sitemaps.views.index')
|
sitemap_url = reverse('django.contrib.sitemaps.views.index')
|
||||||
except urlresolvers.NoReverseMatch:
|
except NoReverseMatch:
|
||||||
try:
|
try:
|
||||||
# Next, try for the "global" sitemap URL.
|
# Next, try for the "global" sitemap URL.
|
||||||
sitemap_url = urlresolvers.reverse('django.contrib.sitemaps.views.sitemap')
|
sitemap_url = reverse('django.contrib.sitemaps.views.sitemap')
|
||||||
except urlresolvers.NoReverseMatch:
|
except NoReverseMatch:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
if sitemap_url is None:
|
if sitemap_url is None:
|
||||||
|
|
|
@ -3,10 +3,10 @@ from calendar import timegm
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
|
|
||||||
from django.contrib.sites.shortcuts import get_current_site
|
from django.contrib.sites.shortcuts import get_current_site
|
||||||
from django.core import urlresolvers
|
|
||||||
from django.core.paginator import EmptyPage, PageNotAnInteger
|
from django.core.paginator import EmptyPage, PageNotAnInteger
|
||||||
from django.http import Http404
|
from django.http import Http404
|
||||||
from django.template.response import TemplateResponse
|
from django.template.response import TemplateResponse
|
||||||
|
from django.urls import reverse
|
||||||
from django.utils.http import http_date
|
from django.utils.http import http_date
|
||||||
|
|
||||||
|
|
||||||
|
@ -32,8 +32,7 @@ def index(request, sitemaps,
|
||||||
if callable(site):
|
if callable(site):
|
||||||
site = site()
|
site = site()
|
||||||
protocol = req_protocol if site.protocol is None else site.protocol
|
protocol = req_protocol if site.protocol is None else site.protocol
|
||||||
sitemap_url = urlresolvers.reverse(
|
sitemap_url = reverse(sitemap_url_name, kwargs={'section': section})
|
||||||
sitemap_url_name, kwargs={'section': section})
|
|
||||||
absolute_url = '%s://%s%s' % (protocol, req_site.domain, sitemap_url)
|
absolute_url = '%s://%s%s' % (protocol, req_site.domain, sitemap_url)
|
||||||
sites.append(absolute_url)
|
sites.append(absolute_url)
|
||||||
for page in range(2, site.paginator.num_pages + 1):
|
for page in range(2, site.paginator.num_pages + 1):
|
||||||
|
|
|
@ -5,7 +5,7 @@ from . import Tags, Warning, register
|
||||||
|
|
||||||
@register(Tags.urls)
|
@register(Tags.urls)
|
||||||
def check_url_config(app_configs, **kwargs):
|
def check_url_config(app_configs, **kwargs):
|
||||||
from django.core.urlresolvers import get_resolver
|
from django.urls import get_resolver
|
||||||
resolver = get_resolver()
|
resolver = get_resolver()
|
||||||
return check_resolver(resolver)
|
return check_resolver(resolver)
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ def check_resolver(resolver):
|
||||||
"""
|
"""
|
||||||
Recursively check the resolver.
|
Recursively check the resolver.
|
||||||
"""
|
"""
|
||||||
from django.core.urlresolvers import RegexURLPattern, RegexURLResolver
|
from django.urls import RegexURLPattern, RegexURLResolver
|
||||||
warnings = []
|
warnings = []
|
||||||
for pattern in resolver.url_patterns:
|
for pattern in resolver.url_patterns:
|
||||||
if isinstance(pattern, RegexURLResolver):
|
if isinstance(pattern, RegexURLResolver):
|
||||||
|
|
|
@ -7,12 +7,13 @@ import warnings
|
||||||
|
|
||||||
from django import http
|
from django import http
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core import signals, urlresolvers
|
from django.core import signals
|
||||||
from django.core.exceptions import (
|
from django.core.exceptions import (
|
||||||
MiddlewareNotUsed, PermissionDenied, SuspiciousOperation,
|
MiddlewareNotUsed, PermissionDenied, SuspiciousOperation,
|
||||||
)
|
)
|
||||||
from django.db import connections, transaction
|
from django.db import connections, transaction
|
||||||
from django.http.multipartparser import MultiPartParserError
|
from django.http.multipartparser import MultiPartParserError
|
||||||
|
from django.urls import get_resolver, set_urlconf
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
from django.utils.deprecation import RemovedInDjango20Warning
|
from django.utils.deprecation import RemovedInDjango20Warning
|
||||||
from django.utils.encoding import force_text
|
from django.utils.encoding import force_text
|
||||||
|
@ -111,8 +112,8 @@ class BaseHandler(object):
|
||||||
# variable" exception in the event an exception is raised before
|
# variable" exception in the event an exception is raised before
|
||||||
# resolver is set
|
# resolver is set
|
||||||
urlconf = settings.ROOT_URLCONF
|
urlconf = settings.ROOT_URLCONF
|
||||||
urlresolvers.set_urlconf(urlconf)
|
set_urlconf(urlconf)
|
||||||
resolver = urlresolvers.get_resolver(urlconf)
|
resolver = get_resolver(urlconf)
|
||||||
# Use a flag to check if the response was rendered to prevent
|
# Use a flag to check if the response was rendered to prevent
|
||||||
# multiple renderings or to force rendering if necessary.
|
# multiple renderings or to force rendering if necessary.
|
||||||
response_is_rendered = False
|
response_is_rendered = False
|
||||||
|
@ -128,8 +129,8 @@ class BaseHandler(object):
|
||||||
if hasattr(request, 'urlconf'):
|
if hasattr(request, 'urlconf'):
|
||||||
# Reset url resolver with a custom URLconf.
|
# Reset url resolver with a custom URLconf.
|
||||||
urlconf = request.urlconf
|
urlconf = request.urlconf
|
||||||
urlresolvers.set_urlconf(urlconf)
|
set_urlconf(urlconf)
|
||||||
resolver = urlresolvers.get_resolver(urlconf)
|
resolver = get_resolver(urlconf)
|
||||||
|
|
||||||
resolver_match = resolver.resolve(request.path_info)
|
resolver_match = resolver.resolve(request.path_info)
|
||||||
callback, callback_args, callback_kwargs = resolver_match
|
callback, callback_args, callback_kwargs = resolver_match
|
||||||
|
|
|
@ -12,7 +12,7 @@ from django import http
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core import signals
|
from django.core import signals
|
||||||
from django.core.handlers import base
|
from django.core.handlers import base
|
||||||
from django.core.urlresolvers import set_script_prefix
|
from django.urls import set_script_prefix
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
from django.utils.encoding import force_str, force_text
|
from django.utils.encoding import force_str, force_text
|
||||||
from django.utils.functional import cached_property
|
from django.utils.functional import cached_property
|
||||||
|
|
|
@ -1,640 +1,9 @@
|
||||||
"""
|
import warnings
|
||||||
This module converts requested URLs to callback view functions.
|
|
||||||
|
|
||||||
RegexURLResolver is the main class here. Its resolve() method takes a URL (as
|
from django.urls import * # NOQA
|
||||||
a string) and returns a ResolverMatch object which provides access to all
|
from django.utils.deprecation import RemovedInDjango20Warning
|
||||||
attributes of the resolved URL match.
|
|
||||||
"""
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
|
|
||||||
import functools
|
warnings.warn(
|
||||||
import re
|
"Importing from django.core.urlresolvers is deprecated in favor of "
|
||||||
from importlib import import_module
|
"django.urls.", RemovedInDjango20Warning, stacklevel=2
|
||||||
from threading import local
|
)
|
||||||
|
|
||||||
from django.core.exceptions import ImproperlyConfigured, ViewDoesNotExist
|
|
||||||
from django.http import Http404
|
|
||||||
from django.utils import lru_cache, six
|
|
||||||
from django.utils.datastructures import MultiValueDict
|
|
||||||
from django.utils.encoding import force_str, force_text, iri_to_uri
|
|
||||||
from django.utils.functional import cached_property, lazy
|
|
||||||
from django.utils.http import RFC3986_SUBDELIMS, urlquote
|
|
||||||
from django.utils.module_loading import module_has_submodule
|
|
||||||
from django.utils.regex_helper import normalize
|
|
||||||
from django.utils.six.moves.urllib.parse import urlsplit, urlunsplit
|
|
||||||
from django.utils.translation import get_language, override
|
|
||||||
|
|
||||||
# SCRIPT_NAME prefixes for each thread are stored here. If there's no entry for
|
|
||||||
# the current thread (which is the only one we ever access), it is assumed to
|
|
||||||
# be empty.
|
|
||||||
_prefixes = local()
|
|
||||||
|
|
||||||
# Overridden URLconfs for each thread are stored here.
|
|
||||||
_urlconfs = local()
|
|
||||||
|
|
||||||
|
|
||||||
class ResolverMatch(object):
|
|
||||||
def __init__(self, func, args, kwargs, url_name=None, app_names=None, namespaces=None):
|
|
||||||
self.func = func
|
|
||||||
self.args = args
|
|
||||||
self.kwargs = kwargs
|
|
||||||
self.url_name = url_name
|
|
||||||
|
|
||||||
# If a URLRegexResolver doesn't have a namespace or app_name, it passes
|
|
||||||
# in an empty value.
|
|
||||||
self.app_names = [x for x in app_names if x] if app_names else []
|
|
||||||
self.app_name = ':'.join(self.app_names)
|
|
||||||
|
|
||||||
if namespaces:
|
|
||||||
self.namespaces = [x for x in namespaces if x]
|
|
||||||
else:
|
|
||||||
self.namespaces = []
|
|
||||||
self.namespace = ':'.join(self.namespaces)
|
|
||||||
|
|
||||||
if not hasattr(func, '__name__'):
|
|
||||||
# A class-based view
|
|
||||||
self._func_path = '.'.join([func.__class__.__module__, func.__class__.__name__])
|
|
||||||
else:
|
|
||||||
# A function-based view
|
|
||||||
self._func_path = '.'.join([func.__module__, func.__name__])
|
|
||||||
|
|
||||||
view_path = url_name or self._func_path
|
|
||||||
self.view_name = ':'.join(self.namespaces + [view_path])
|
|
||||||
|
|
||||||
def __getitem__(self, index):
|
|
||||||
return (self.func, self.args, self.kwargs)[index]
|
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
return "ResolverMatch(func=%s, args=%s, kwargs=%s, url_name=%s, app_names=%s, namespaces=%s)" % (
|
|
||||||
self._func_path, self.args, self.kwargs, self.url_name, self.app_names, self.namespaces)
|
|
||||||
|
|
||||||
|
|
||||||
class Resolver404(Http404):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class NoReverseMatch(Exception):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
@lru_cache.lru_cache(maxsize=None)
|
|
||||||
def get_callable(lookup_view):
|
|
||||||
"""
|
|
||||||
Return a callable corresponding to lookup_view.
|
|
||||||
|
|
||||||
* If lookup_view is already a callable, return it.
|
|
||||||
* If lookup_view is a string import path that can be resolved to a callable,
|
|
||||||
import that callable and return it, otherwise raise an exception
|
|
||||||
(ImportError or ViewDoesNotExist).
|
|
||||||
"""
|
|
||||||
if callable(lookup_view):
|
|
||||||
return lookup_view
|
|
||||||
|
|
||||||
if not isinstance(lookup_view, six.string_types):
|
|
||||||
raise ViewDoesNotExist("'%s' is not a callable or a dot-notation path" % lookup_view)
|
|
||||||
|
|
||||||
mod_name, func_name = get_mod_func(lookup_view)
|
|
||||||
if not func_name: # No '.' in lookup_view
|
|
||||||
raise ImportError("Could not import '%s'. The path must be fully qualified." % lookup_view)
|
|
||||||
|
|
||||||
try:
|
|
||||||
mod = import_module(mod_name)
|
|
||||||
except ImportError:
|
|
||||||
parentmod, submod = get_mod_func(mod_name)
|
|
||||||
if submod and not module_has_submodule(import_module(parentmod), submod):
|
|
||||||
raise ViewDoesNotExist(
|
|
||||||
"Could not import '%s'. Parent module %s does not exist." %
|
|
||||||
(lookup_view, mod_name)
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
raise
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
view_func = getattr(mod, func_name)
|
|
||||||
except AttributeError:
|
|
||||||
raise ViewDoesNotExist(
|
|
||||||
"Could not import '%s'. View does not exist in module %s." %
|
|
||||||
(lookup_view, mod_name)
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
if not callable(view_func):
|
|
||||||
raise ViewDoesNotExist(
|
|
||||||
"Could not import '%s.%s'. View is not callable." %
|
|
||||||
(mod_name, func_name)
|
|
||||||
)
|
|
||||||
return view_func
|
|
||||||
|
|
||||||
|
|
||||||
@lru_cache.lru_cache(maxsize=None)
|
|
||||||
def get_resolver(urlconf=None):
|
|
||||||
if urlconf is None:
|
|
||||||
from django.conf import settings
|
|
||||||
urlconf = settings.ROOT_URLCONF
|
|
||||||
return RegexURLResolver(r'^/', urlconf)
|
|
||||||
|
|
||||||
|
|
||||||
@lru_cache.lru_cache(maxsize=None)
|
|
||||||
def get_ns_resolver(ns_pattern, resolver):
|
|
||||||
# Build a namespaced resolver for the given parent URLconf pattern.
|
|
||||||
# This makes it possible to have captured parameters in the parent
|
|
||||||
# URLconf pattern.
|
|
||||||
ns_resolver = RegexURLResolver(ns_pattern, resolver.url_patterns)
|
|
||||||
return RegexURLResolver(r'^/', [ns_resolver])
|
|
||||||
|
|
||||||
|
|
||||||
def get_mod_func(callback):
|
|
||||||
# Converts 'django.views.news.stories.story_detail' to
|
|
||||||
# ['django.views.news.stories', 'story_detail']
|
|
||||||
try:
|
|
||||||
dot = callback.rindex('.')
|
|
||||||
except ValueError:
|
|
||||||
return callback, ''
|
|
||||||
return callback[:dot], callback[dot + 1:]
|
|
||||||
|
|
||||||
|
|
||||||
class LocaleRegexProvider(object):
|
|
||||||
"""
|
|
||||||
A mixin to provide a default regex property which can vary by active
|
|
||||||
language.
|
|
||||||
"""
|
|
||||||
def __init__(self, regex):
|
|
||||||
# regex is either a string representing a regular expression, or a
|
|
||||||
# translatable string (using ugettext_lazy) representing a regular
|
|
||||||
# expression.
|
|
||||||
self._regex = regex
|
|
||||||
self._regex_dict = {}
|
|
||||||
|
|
||||||
@property
|
|
||||||
def regex(self):
|
|
||||||
"""
|
|
||||||
Returns a compiled regular expression, depending upon the activated
|
|
||||||
language-code.
|
|
||||||
"""
|
|
||||||
language_code = get_language()
|
|
||||||
if language_code not in self._regex_dict:
|
|
||||||
if isinstance(self._regex, six.string_types):
|
|
||||||
regex = self._regex
|
|
||||||
else:
|
|
||||||
regex = force_text(self._regex)
|
|
||||||
try:
|
|
||||||
compiled_regex = re.compile(regex, re.UNICODE)
|
|
||||||
except re.error as e:
|
|
||||||
raise ImproperlyConfigured(
|
|
||||||
'"%s" is not a valid regular expression: %s' %
|
|
||||||
(regex, six.text_type(e)))
|
|
||||||
|
|
||||||
self._regex_dict[language_code] = compiled_regex
|
|
||||||
return self._regex_dict[language_code]
|
|
||||||
|
|
||||||
|
|
||||||
class RegexURLPattern(LocaleRegexProvider):
|
|
||||||
def __init__(self, regex, callback, default_args=None, name=None):
|
|
||||||
LocaleRegexProvider.__init__(self, regex)
|
|
||||||
self.callback = callback # the view
|
|
||||||
self.default_args = default_args or {}
|
|
||||||
self.name = name
|
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
return force_str('<%s %s %s>' % (self.__class__.__name__, self.name, self.regex.pattern))
|
|
||||||
|
|
||||||
def resolve(self, path):
|
|
||||||
match = self.regex.search(path)
|
|
||||||
if match:
|
|
||||||
# If there are any named groups, use those as kwargs, ignoring
|
|
||||||
# non-named groups. Otherwise, pass all non-named arguments as
|
|
||||||
# positional arguments.
|
|
||||||
kwargs = match.groupdict()
|
|
||||||
if kwargs:
|
|
||||||
args = ()
|
|
||||||
else:
|
|
||||||
args = match.groups()
|
|
||||||
# In both cases, pass any extra_kwargs as **kwargs.
|
|
||||||
kwargs.update(self.default_args)
|
|
||||||
|
|
||||||
return ResolverMatch(self.callback, args, kwargs, self.name)
|
|
||||||
|
|
||||||
@cached_property
|
|
||||||
def lookup_str(self):
|
|
||||||
"""
|
|
||||||
A string that identifies the view (e.g. 'path.to.view_function' or
|
|
||||||
'path.to.ClassBasedView').
|
|
||||||
"""
|
|
||||||
callback = self.callback
|
|
||||||
if isinstance(callback, functools.partial):
|
|
||||||
callback = callback.func
|
|
||||||
if not hasattr(callback, '__name__'):
|
|
||||||
return callback.__module__ + "." + callback.__class__.__name__
|
|
||||||
else:
|
|
||||||
return callback.__module__ + "." + callback.__name__
|
|
||||||
|
|
||||||
|
|
||||||
class RegexURLResolver(LocaleRegexProvider):
|
|
||||||
def __init__(self, regex, urlconf_name, default_kwargs=None, app_name=None, namespace=None):
|
|
||||||
LocaleRegexProvider.__init__(self, regex)
|
|
||||||
# urlconf_name is the dotted Python path to the module defining
|
|
||||||
# urlpatterns. It may also be an object with an urlpatterns attribute
|
|
||||||
# or urlpatterns itself.
|
|
||||||
self.urlconf_name = urlconf_name
|
|
||||||
self.callback = None
|
|
||||||
self.default_kwargs = default_kwargs or {}
|
|
||||||
self.namespace = namespace
|
|
||||||
self.app_name = app_name
|
|
||||||
self._reverse_dict = {}
|
|
||||||
self._namespace_dict = {}
|
|
||||||
self._app_dict = {}
|
|
||||||
# set of dotted paths to all functions and classes that are used in
|
|
||||||
# urlpatterns
|
|
||||||
self._callback_strs = set()
|
|
||||||
self._populated = False
|
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
if isinstance(self.urlconf_name, list) and len(self.urlconf_name):
|
|
||||||
# Don't bother to output the whole list, it can be huge
|
|
||||||
urlconf_repr = '<%s list>' % self.urlconf_name[0].__class__.__name__
|
|
||||||
else:
|
|
||||||
urlconf_repr = repr(self.urlconf_name)
|
|
||||||
return str('<%s %s (%s:%s) %s>') % (
|
|
||||||
self.__class__.__name__, urlconf_repr, self.app_name,
|
|
||||||
self.namespace, self.regex.pattern)
|
|
||||||
|
|
||||||
def _populate(self):
|
|
||||||
lookups = MultiValueDict()
|
|
||||||
namespaces = {}
|
|
||||||
apps = {}
|
|
||||||
language_code = get_language()
|
|
||||||
for pattern in reversed(self.url_patterns):
|
|
||||||
if isinstance(pattern, RegexURLPattern):
|
|
||||||
self._callback_strs.add(pattern.lookup_str)
|
|
||||||
p_pattern = pattern.regex.pattern
|
|
||||||
if p_pattern.startswith('^'):
|
|
||||||
p_pattern = p_pattern[1:]
|
|
||||||
if isinstance(pattern, RegexURLResolver):
|
|
||||||
if pattern.namespace:
|
|
||||||
namespaces[pattern.namespace] = (p_pattern, pattern)
|
|
||||||
if pattern.app_name:
|
|
||||||
apps.setdefault(pattern.app_name, []).append(pattern.namespace)
|
|
||||||
else:
|
|
||||||
parent_pat = pattern.regex.pattern
|
|
||||||
for name in pattern.reverse_dict:
|
|
||||||
for matches, pat, defaults in pattern.reverse_dict.getlist(name):
|
|
||||||
new_matches = normalize(parent_pat + pat)
|
|
||||||
lookups.appendlist(
|
|
||||||
name,
|
|
||||||
(
|
|
||||||
new_matches,
|
|
||||||
p_pattern + pat,
|
|
||||||
dict(defaults, **pattern.default_kwargs),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
for namespace, (prefix, sub_pattern) in pattern.namespace_dict.items():
|
|
||||||
namespaces[namespace] = (p_pattern + prefix, sub_pattern)
|
|
||||||
for app_name, namespace_list in pattern.app_dict.items():
|
|
||||||
apps.setdefault(app_name, []).extend(namespace_list)
|
|
||||||
self._callback_strs.update(pattern._callback_strs)
|
|
||||||
else:
|
|
||||||
bits = normalize(p_pattern)
|
|
||||||
lookups.appendlist(pattern.callback, (bits, p_pattern, pattern.default_args))
|
|
||||||
if pattern.name is not None:
|
|
||||||
lookups.appendlist(pattern.name, (bits, p_pattern, pattern.default_args))
|
|
||||||
self._reverse_dict[language_code] = lookups
|
|
||||||
self._namespace_dict[language_code] = namespaces
|
|
||||||
self._app_dict[language_code] = apps
|
|
||||||
self._populated = True
|
|
||||||
|
|
||||||
@property
|
|
||||||
def reverse_dict(self):
|
|
||||||
language_code = get_language()
|
|
||||||
if language_code not in self._reverse_dict:
|
|
||||||
self._populate()
|
|
||||||
return self._reverse_dict[language_code]
|
|
||||||
|
|
||||||
@property
|
|
||||||
def namespace_dict(self):
|
|
||||||
language_code = get_language()
|
|
||||||
if language_code not in self._namespace_dict:
|
|
||||||
self._populate()
|
|
||||||
return self._namespace_dict[language_code]
|
|
||||||
|
|
||||||
@property
|
|
||||||
def app_dict(self):
|
|
||||||
language_code = get_language()
|
|
||||||
if language_code not in self._app_dict:
|
|
||||||
self._populate()
|
|
||||||
return self._app_dict[language_code]
|
|
||||||
|
|
||||||
def _is_callback(self, name):
|
|
||||||
if not self._populated:
|
|
||||||
self._populate()
|
|
||||||
return name in self._callback_strs
|
|
||||||
|
|
||||||
def resolve(self, path):
|
|
||||||
path = force_text(path) # path may be a reverse_lazy object
|
|
||||||
tried = []
|
|
||||||
match = self.regex.search(path)
|
|
||||||
if match:
|
|
||||||
new_path = path[match.end():]
|
|
||||||
for pattern in self.url_patterns:
|
|
||||||
try:
|
|
||||||
sub_match = pattern.resolve(new_path)
|
|
||||||
except Resolver404 as e:
|
|
||||||
sub_tried = e.args[0].get('tried')
|
|
||||||
if sub_tried is not None:
|
|
||||||
tried.extend([pattern] + t for t in sub_tried)
|
|
||||||
else:
|
|
||||||
tried.append([pattern])
|
|
||||||
else:
|
|
||||||
if sub_match:
|
|
||||||
# Merge captured arguments in match with submatch
|
|
||||||
sub_match_dict = dict(match.groupdict(), **self.default_kwargs)
|
|
||||||
sub_match_dict.update(sub_match.kwargs)
|
|
||||||
|
|
||||||
# If there are *any* named groups, ignore all non-named groups.
|
|
||||||
# Otherwise, pass all non-named arguments as positional arguments.
|
|
||||||
sub_match_args = sub_match.args
|
|
||||||
if not sub_match_dict:
|
|
||||||
sub_match_args = match.groups() + sub_match.args
|
|
||||||
|
|
||||||
return ResolverMatch(
|
|
||||||
sub_match.func,
|
|
||||||
sub_match_args,
|
|
||||||
sub_match_dict,
|
|
||||||
sub_match.url_name,
|
|
||||||
[self.app_name] + sub_match.app_names,
|
|
||||||
[self.namespace] + sub_match.namespaces
|
|
||||||
)
|
|
||||||
tried.append([pattern])
|
|
||||||
raise Resolver404({'tried': tried, 'path': new_path})
|
|
||||||
raise Resolver404({'path': path})
|
|
||||||
|
|
||||||
@cached_property
|
|
||||||
def urlconf_module(self):
|
|
||||||
if isinstance(self.urlconf_name, six.string_types):
|
|
||||||
return import_module(self.urlconf_name)
|
|
||||||
else:
|
|
||||||
return self.urlconf_name
|
|
||||||
|
|
||||||
@cached_property
|
|
||||||
def url_patterns(self):
|
|
||||||
# urlconf_module might be a valid set of patterns, so we default to it
|
|
||||||
patterns = getattr(self.urlconf_module, "urlpatterns", self.urlconf_module)
|
|
||||||
try:
|
|
||||||
iter(patterns)
|
|
||||||
except TypeError:
|
|
||||||
msg = (
|
|
||||||
"The included URLconf '{name}' does not appear to have any "
|
|
||||||
"patterns in it. If you see valid patterns in the file then "
|
|
||||||
"the issue is probably caused by a circular import."
|
|
||||||
)
|
|
||||||
raise ImproperlyConfigured(msg.format(name=self.urlconf_name))
|
|
||||||
return patterns
|
|
||||||
|
|
||||||
def resolve_error_handler(self, view_type):
|
|
||||||
callback = getattr(self.urlconf_module, 'handler%s' % view_type, None)
|
|
||||||
if not callback:
|
|
||||||
# No handler specified in file; use default
|
|
||||||
# Lazy import, since django.urls imports this file
|
|
||||||
from django.conf import urls
|
|
||||||
callback = getattr(urls, 'handler%s' % view_type)
|
|
||||||
return get_callable(callback), {}
|
|
||||||
|
|
||||||
def _reverse_with_prefix(self, lookup_view, _prefix, *args, **kwargs):
|
|
||||||
if args and kwargs:
|
|
||||||
raise ValueError("Don't mix *args and **kwargs in call to reverse()!")
|
|
||||||
text_args = [force_text(v) for v in args]
|
|
||||||
text_kwargs = {k: force_text(v) for (k, v) in kwargs.items()}
|
|
||||||
|
|
||||||
if not self._populated:
|
|
||||||
self._populate()
|
|
||||||
|
|
||||||
possibilities = self.reverse_dict.getlist(lookup_view)
|
|
||||||
|
|
||||||
for possibility, pattern, defaults in possibilities:
|
|
||||||
for result, params in possibility:
|
|
||||||
if args:
|
|
||||||
if len(args) != len(params):
|
|
||||||
continue
|
|
||||||
candidate_subs = dict(zip(params, text_args))
|
|
||||||
else:
|
|
||||||
if (set(kwargs.keys()) | set(defaults.keys()) != set(params) |
|
|
||||||
set(defaults.keys())):
|
|
||||||
continue
|
|
||||||
matches = True
|
|
||||||
for k, v in defaults.items():
|
|
||||||
if kwargs.get(k, v) != v:
|
|
||||||
matches = False
|
|
||||||
break
|
|
||||||
if not matches:
|
|
||||||
continue
|
|
||||||
candidate_subs = text_kwargs
|
|
||||||
# WSGI provides decoded URLs, without %xx escapes, and the URL
|
|
||||||
# resolver operates on such URLs. First substitute arguments
|
|
||||||
# without quoting to build a decoded URL and look for a match.
|
|
||||||
# Then, if we have a match, redo the substitution with quoted
|
|
||||||
# arguments in order to return a properly encoded URL.
|
|
||||||
candidate_pat = _prefix.replace('%', '%%') + result
|
|
||||||
if re.search('^%s%s' % (re.escape(_prefix), pattern), candidate_pat % candidate_subs, re.UNICODE):
|
|
||||||
# safe characters from `pchar` definition of RFC 3986
|
|
||||||
url = urlquote(candidate_pat % candidate_subs, safe=RFC3986_SUBDELIMS + str('/~:@'))
|
|
||||||
# Don't allow construction of scheme relative urls.
|
|
||||||
if url.startswith('//'):
|
|
||||||
url = '/%%2F%s' % url[2:]
|
|
||||||
return url
|
|
||||||
# lookup_view can be URL name or callable, but callables are not
|
|
||||||
# friendly in error messages.
|
|
||||||
m = getattr(lookup_view, '__module__', None)
|
|
||||||
n = getattr(lookup_view, '__name__', None)
|
|
||||||
if m is not None and n is not None:
|
|
||||||
lookup_view_s = "%s.%s" % (m, n)
|
|
||||||
else:
|
|
||||||
lookup_view_s = lookup_view
|
|
||||||
|
|
||||||
patterns = [pattern for (possibility, pattern, defaults) in possibilities]
|
|
||||||
raise NoReverseMatch("Reverse for '%s' with arguments '%s' and keyword "
|
|
||||||
"arguments '%s' not found. %d pattern(s) tried: %s" %
|
|
||||||
(lookup_view_s, args, kwargs, len(patterns), patterns))
|
|
||||||
|
|
||||||
|
|
||||||
class LocaleRegexURLResolver(RegexURLResolver):
|
|
||||||
"""
|
|
||||||
A URL resolver that always matches the active language code as URL prefix.
|
|
||||||
|
|
||||||
Rather than taking a regex argument, we just override the ``regex``
|
|
||||||
function to always return the active language-code as regex.
|
|
||||||
"""
|
|
||||||
def __init__(self, urlconf_name, default_kwargs=None, app_name=None, namespace=None):
|
|
||||||
super(LocaleRegexURLResolver, self).__init__(
|
|
||||||
None, urlconf_name, default_kwargs, app_name, namespace)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def regex(self):
|
|
||||||
language_code = get_language()
|
|
||||||
if language_code not in self._regex_dict:
|
|
||||||
regex_compiled = re.compile('^%s/' % language_code, re.UNICODE)
|
|
||||||
self._regex_dict[language_code] = regex_compiled
|
|
||||||
return self._regex_dict[language_code]
|
|
||||||
|
|
||||||
|
|
||||||
def resolve(path, urlconf=None):
|
|
||||||
if urlconf is None:
|
|
||||||
urlconf = get_urlconf()
|
|
||||||
return get_resolver(urlconf).resolve(path)
|
|
||||||
|
|
||||||
|
|
||||||
def reverse(viewname, urlconf=None, args=None, kwargs=None, current_app=None):
|
|
||||||
if urlconf is None:
|
|
||||||
urlconf = get_urlconf()
|
|
||||||
resolver = get_resolver(urlconf)
|
|
||||||
args = args or []
|
|
||||||
kwargs = kwargs or {}
|
|
||||||
|
|
||||||
prefix = get_script_prefix()
|
|
||||||
|
|
||||||
if not isinstance(viewname, six.string_types):
|
|
||||||
view = viewname
|
|
||||||
else:
|
|
||||||
parts = viewname.split(':')
|
|
||||||
parts.reverse()
|
|
||||||
view = parts[0]
|
|
||||||
path = parts[1:]
|
|
||||||
|
|
||||||
if current_app:
|
|
||||||
current_path = current_app.split(':')
|
|
||||||
current_path.reverse()
|
|
||||||
else:
|
|
||||||
current_path = None
|
|
||||||
|
|
||||||
resolved_path = []
|
|
||||||
ns_pattern = ''
|
|
||||||
while path:
|
|
||||||
ns = path.pop()
|
|
||||||
current_ns = current_path.pop() if current_path else None
|
|
||||||
|
|
||||||
# Lookup the name to see if it could be an app identifier
|
|
||||||
try:
|
|
||||||
app_list = resolver.app_dict[ns]
|
|
||||||
# Yes! Path part matches an app in the current Resolver
|
|
||||||
if current_ns and current_ns in app_list:
|
|
||||||
# If we are reversing for a particular app,
|
|
||||||
# use that namespace
|
|
||||||
ns = current_ns
|
|
||||||
elif ns not in app_list:
|
|
||||||
# The name isn't shared by one of the instances
|
|
||||||
# (i.e., the default) so just pick the first instance
|
|
||||||
# as the default.
|
|
||||||
ns = app_list[0]
|
|
||||||
except KeyError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
if ns != current_ns:
|
|
||||||
current_path = None
|
|
||||||
|
|
||||||
try:
|
|
||||||
extra, resolver = resolver.namespace_dict[ns]
|
|
||||||
resolved_path.append(ns)
|
|
||||||
ns_pattern = ns_pattern + extra
|
|
||||||
except KeyError as key:
|
|
||||||
if resolved_path:
|
|
||||||
raise NoReverseMatch(
|
|
||||||
"%s is not a registered namespace inside '%s'" %
|
|
||||||
(key, ':'.join(resolved_path)))
|
|
||||||
else:
|
|
||||||
raise NoReverseMatch("%s is not a registered namespace" %
|
|
||||||
key)
|
|
||||||
if ns_pattern:
|
|
||||||
resolver = get_ns_resolver(ns_pattern, resolver)
|
|
||||||
|
|
||||||
return force_text(iri_to_uri(resolver._reverse_with_prefix(view, prefix, *args, **kwargs)))
|
|
||||||
|
|
||||||
reverse_lazy = lazy(reverse, six.text_type)
|
|
||||||
|
|
||||||
|
|
||||||
def clear_url_caches():
|
|
||||||
get_callable.cache_clear()
|
|
||||||
get_resolver.cache_clear()
|
|
||||||
get_ns_resolver.cache_clear()
|
|
||||||
|
|
||||||
|
|
||||||
def set_script_prefix(prefix):
|
|
||||||
"""
|
|
||||||
Sets the script prefix for the current thread.
|
|
||||||
"""
|
|
||||||
if not prefix.endswith('/'):
|
|
||||||
prefix += '/'
|
|
||||||
_prefixes.value = prefix
|
|
||||||
|
|
||||||
|
|
||||||
def get_script_prefix():
|
|
||||||
"""
|
|
||||||
Returns the currently active script prefix. Useful for client code that
|
|
||||||
wishes to construct their own URLs manually (although accessing the request
|
|
||||||
instance is normally going to be a lot cleaner).
|
|
||||||
"""
|
|
||||||
return getattr(_prefixes, "value", '/')
|
|
||||||
|
|
||||||
|
|
||||||
def clear_script_prefix():
|
|
||||||
"""
|
|
||||||
Unsets the script prefix for the current thread.
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
del _prefixes.value
|
|
||||||
except AttributeError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
def set_urlconf(urlconf_name):
|
|
||||||
"""
|
|
||||||
Sets the URLconf for the current thread (overriding the default one in
|
|
||||||
settings). Set to None to revert back to the default.
|
|
||||||
"""
|
|
||||||
if urlconf_name:
|
|
||||||
_urlconfs.value = urlconf_name
|
|
||||||
else:
|
|
||||||
if hasattr(_urlconfs, "value"):
|
|
||||||
del _urlconfs.value
|
|
||||||
|
|
||||||
|
|
||||||
def get_urlconf(default=None):
|
|
||||||
"""
|
|
||||||
Returns the root URLconf to use for the current thread if it has been
|
|
||||||
changed from the default one.
|
|
||||||
"""
|
|
||||||
return getattr(_urlconfs, "value", default)
|
|
||||||
|
|
||||||
|
|
||||||
def is_valid_path(path, urlconf=None):
|
|
||||||
"""
|
|
||||||
Returns True if the given path resolves against the default URL resolver,
|
|
||||||
False otherwise.
|
|
||||||
|
|
||||||
This is a convenience method to make working with "is this a match?" cases
|
|
||||||
easier, avoiding unnecessarily indented try...except blocks.
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
resolve(path, urlconf)
|
|
||||||
return True
|
|
||||||
except Resolver404:
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def translate_url(url, lang_code):
|
|
||||||
"""
|
|
||||||
Given a URL (absolute or relative), try to get its translated version in
|
|
||||||
the `lang_code` language (either by i18n_patterns or by translated regex).
|
|
||||||
Return the original URL if no translated version is found.
|
|
||||||
"""
|
|
||||||
parsed = urlsplit(url)
|
|
||||||
try:
|
|
||||||
match = resolve(parsed.path)
|
|
||||||
except Resolver404:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
to_be_reversed = "%s:%s" % (match.namespace, match.url_name) if match.namespace else match.url_name
|
|
||||||
with override(lang_code):
|
|
||||||
try:
|
|
||||||
url = reverse(to_be_reversed, args=match.args, kwargs=match.kwargs)
|
|
||||||
except NoReverseMatch:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
url = urlunsplit((parsed.scheme, parsed.netloc, url, parsed.query, parsed.fragment))
|
|
||||||
return url
|
|
||||||
|
|
|
@ -26,15 +26,15 @@ from django.db.models.fields.related import ( # NOQA isort:skip
|
||||||
|
|
||||||
def permalink(func):
|
def permalink(func):
|
||||||
"""
|
"""
|
||||||
Decorator that calls urlresolvers.reverse() to return a URL using
|
Decorator that calls urls.reverse() to return a URL using parameters
|
||||||
parameters returned by the decorated function "func".
|
returned by the decorated function "func".
|
||||||
|
|
||||||
"func" should be a function that returns a tuple in one of the
|
"func" should be a function that returns a tuple in one of the
|
||||||
following formats:
|
following formats:
|
||||||
(viewname, viewargs)
|
(viewname, viewargs)
|
||||||
(viewname, viewargs, viewkwargs)
|
(viewname, viewargs, viewkwargs)
|
||||||
"""
|
"""
|
||||||
from django.core.urlresolvers import reverse
|
from django.urls import reverse
|
||||||
|
|
||||||
@wraps(func)
|
@wraps(func)
|
||||||
def inner(*args, **kwargs):
|
def inner(*args, **kwargs):
|
||||||
|
|
|
@ -3,9 +3,9 @@ import re
|
||||||
|
|
||||||
from django import http
|
from django import http
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core import urlresolvers
|
|
||||||
from django.core.exceptions import PermissionDenied
|
from django.core.exceptions import PermissionDenied
|
||||||
from django.core.mail import mail_managers
|
from django.core.mail import mail_managers
|
||||||
|
from django.urls import is_valid_path
|
||||||
from django.utils.cache import get_conditional_response, set_response_etag
|
from django.utils.cache import get_conditional_response, set_response_etag
|
||||||
from django.utils.encoding import force_text
|
from django.utils.encoding import force_text
|
||||||
from django.utils.six.moves.urllib.parse import urlparse
|
from django.utils.six.moves.urllib.parse import urlparse
|
||||||
|
@ -74,8 +74,8 @@ class CommonMiddleware(object):
|
||||||
if settings.APPEND_SLASH and not request.get_full_path().endswith('/'):
|
if settings.APPEND_SLASH and not request.get_full_path().endswith('/'):
|
||||||
urlconf = getattr(request, 'urlconf', None)
|
urlconf = getattr(request, 'urlconf', None)
|
||||||
return (
|
return (
|
||||||
not urlresolvers.is_valid_path(request.path_info, urlconf)
|
not is_valid_path(request.path_info, urlconf)
|
||||||
and urlresolvers.is_valid_path('%s/' % request.path_info, urlconf)
|
and is_valid_path('%s/' % request.path_info, urlconf)
|
||||||
)
|
)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ import logging
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.urlresolvers import get_callable
|
from django.urls import get_callable
|
||||||
from django.utils.cache import patch_vary_headers
|
from django.utils.cache import patch_vary_headers
|
||||||
from django.utils.crypto import constant_time_compare, get_random_string
|
from django.utils.crypto import constant_time_compare, get_random_string
|
||||||
from django.utils.encoding import force_text
|
from django.utils.encoding import force_text
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
"This is the locale selecting middleware that will look at accept headers"
|
"This is the locale selecting middleware that will look at accept headers"
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.urlresolvers import (
|
from django.http import HttpResponseRedirect
|
||||||
|
from django.urls import (
|
||||||
LocaleRegexURLResolver, get_resolver, get_script_prefix, is_valid_path,
|
LocaleRegexURLResolver, get_resolver, get_script_prefix, is_valid_path,
|
||||||
)
|
)
|
||||||
from django.http import HttpResponseRedirect
|
|
||||||
from django.utils import translation
|
from django.utils import translation
|
||||||
from django.utils.cache import patch_vary_headers
|
from django.utils.cache import patch_vary_headers
|
||||||
from django.utils.functional import cached_property
|
from django.utils.functional import cached_property
|
||||||
|
|
|
@ -3,7 +3,6 @@ This module collects helper functions and classes that "span" multiple levels
|
||||||
of MVC. In other words, these functions/classes introduce controlled coupling
|
of MVC. In other words, these functions/classes introduce controlled coupling
|
||||||
for convenience's sake.
|
for convenience's sake.
|
||||||
"""
|
"""
|
||||||
from django.core import urlresolvers
|
|
||||||
from django.db.models.base import ModelBase
|
from django.db.models.base import ModelBase
|
||||||
from django.db.models.manager import Manager
|
from django.db.models.manager import Manager
|
||||||
from django.db.models.query import QuerySet
|
from django.db.models.query import QuerySet
|
||||||
|
@ -11,6 +10,7 @@ from django.http import (
|
||||||
Http404, HttpResponse, HttpResponsePermanentRedirect, HttpResponseRedirect,
|
Http404, HttpResponse, HttpResponsePermanentRedirect, HttpResponseRedirect,
|
||||||
)
|
)
|
||||||
from django.template import loader
|
from django.template import loader
|
||||||
|
from django.urls import NoReverseMatch, reverse
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
from django.utils.encoding import force_text
|
from django.utils.encoding import force_text
|
||||||
from django.utils.functional import Promise
|
from django.utils.functional import Promise
|
||||||
|
@ -43,8 +43,8 @@ def redirect(to, *args, **kwargs):
|
||||||
|
|
||||||
* A model: the model's `get_absolute_url()` function will be called.
|
* A model: the model's `get_absolute_url()` function will be called.
|
||||||
|
|
||||||
* A view name, possibly with arguments: `urlresolvers.reverse()` will
|
* A view name, possibly with arguments: `urls.reverse()` will be used
|
||||||
be used to reverse-resolve the name.
|
to reverse-resolve the name.
|
||||||
|
|
||||||
* A URL, which will be used as-is for the redirect location.
|
* A URL, which will be used as-is for the redirect location.
|
||||||
|
|
||||||
|
@ -123,8 +123,8 @@ def resolve_url(to, *args, **kwargs):
|
||||||
|
|
||||||
* A model: the model's `get_absolute_url()` function will be called.
|
* A model: the model's `get_absolute_url()` function will be called.
|
||||||
|
|
||||||
* A view name, possibly with arguments: `urlresolvers.reverse()` will
|
* A view name, possibly with arguments: `urls.reverse()` will be used
|
||||||
be used to reverse-resolve the name.
|
to reverse-resolve the name.
|
||||||
|
|
||||||
* A URL, which will be returned as-is.
|
* A URL, which will be returned as-is.
|
||||||
"""
|
"""
|
||||||
|
@ -144,8 +144,8 @@ def resolve_url(to, *args, **kwargs):
|
||||||
|
|
||||||
# Next try a reverse URL resolution.
|
# Next try a reverse URL resolution.
|
||||||
try:
|
try:
|
||||||
return urlresolvers.reverse(to, args=args, kwargs=kwargs)
|
return reverse(to, args=args, kwargs=kwargs)
|
||||||
except urlresolvers.NoReverseMatch:
|
except NoReverseMatch:
|
||||||
# If this is a callable, re-raise.
|
# If this is a callable, re-raise.
|
||||||
if callable(to):
|
if callable(to):
|
||||||
raise
|
raise
|
||||||
|
|
|
@ -426,7 +426,7 @@ class URLNode(Node):
|
||||||
self.asvar = asvar
|
self.asvar = asvar
|
||||||
|
|
||||||
def render(self, context):
|
def render(self, context):
|
||||||
from django.core.urlresolvers import reverse, NoReverseMatch
|
from django.urls import reverse, NoReverseMatch
|
||||||
args = [arg.resolve(context) for arg in self.args]
|
args = [arg.resolve(context) for arg in self.args]
|
||||||
kwargs = {
|
kwargs = {
|
||||||
smart_text(k, 'ascii'): v.resolve(context)
|
smart_text(k, 'ascii'): v.resolve(context)
|
||||||
|
|
|
@ -11,7 +11,6 @@ from io import BytesIO
|
||||||
|
|
||||||
from django.apps import apps
|
from django.apps import apps
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core import urlresolvers
|
|
||||||
from django.core.handlers.base import BaseHandler
|
from django.core.handlers.base import BaseHandler
|
||||||
from django.core.handlers.wsgi import ISO_8859_1, UTF_8, WSGIRequest
|
from django.core.handlers.wsgi import ISO_8859_1, UTF_8, WSGIRequest
|
||||||
from django.core.signals import (
|
from django.core.signals import (
|
||||||
|
@ -22,6 +21,7 @@ from django.http import HttpRequest, QueryDict, SimpleCookie
|
||||||
from django.template import TemplateDoesNotExist
|
from django.template import TemplateDoesNotExist
|
||||||
from django.test import signals
|
from django.test import signals
|
||||||
from django.test.utils import ContextList
|
from django.test.utils import ContextList
|
||||||
|
from django.urls import resolve
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
from django.utils.encoding import force_bytes, force_str, uri_to_iri
|
from django.utils.encoding import force_bytes, force_str, uri_to_iri
|
||||||
from django.utils.functional import SimpleLazyObject, curry
|
from django.utils.functional import SimpleLazyObject, curry
|
||||||
|
@ -477,8 +477,7 @@ class Client(RequestFactory):
|
||||||
response.json = curry(self._parse_json, response)
|
response.json = curry(self._parse_json, response)
|
||||||
|
|
||||||
# Attach the ResolverMatch instance to the response
|
# Attach the ResolverMatch instance to the response
|
||||||
response.resolver_match = SimpleLazyObject(
|
response.resolver_match = SimpleLazyObject(lambda: resolve(request['PATH_INFO']))
|
||||||
lambda: urlresolvers.resolve(request['PATH_INFO']))
|
|
||||||
|
|
||||||
# Flatten a single context. Not really necessary anymore thanks to
|
# Flatten a single context. Not really necessary anymore thanks to
|
||||||
# the __getattr__ flattening in ContextList, but has some edge-case
|
# the __getattr__ flattening in ContextList, but has some edge-case
|
||||||
|
|
|
@ -145,7 +145,7 @@ def complex_setting_changed(**kwargs):
|
||||||
@receiver(setting_changed)
|
@receiver(setting_changed)
|
||||||
def root_urlconf_changed(**kwargs):
|
def root_urlconf_changed(**kwargs):
|
||||||
if kwargs['setting'] == 'ROOT_URLCONF':
|
if kwargs['setting'] == 'ROOT_URLCONF':
|
||||||
from django.core.urlresolvers import clear_url_caches, set_urlconf
|
from django.urls import clear_url_caches, set_urlconf
|
||||||
clear_url_caches()
|
clear_url_caches()
|
||||||
set_urlconf(None)
|
set_urlconf(None)
|
||||||
|
|
||||||
|
|
|
@ -12,11 +12,11 @@ from django.apps import apps
|
||||||
from django.conf import UserSettingsHolder, settings
|
from django.conf import UserSettingsHolder, settings
|
||||||
from django.core import mail
|
from django.core import mail
|
||||||
from django.core.signals import request_started
|
from django.core.signals import request_started
|
||||||
from django.core.urlresolvers import get_script_prefix, set_script_prefix
|
|
||||||
from django.db import reset_queries
|
from django.db import reset_queries
|
||||||
from django.http import request
|
from django.http import request
|
||||||
from django.template import Template
|
from django.template import Template
|
||||||
from django.test.signals import setting_changed, template_rendered
|
from django.test.signals import setting_changed, template_rendered
|
||||||
|
from django.urls import get_script_prefix, set_script_prefix
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
from django.utils.decorators import ContextDecorator
|
from django.utils.decorators import ContextDecorator
|
||||||
from django.utils.encoding import force_str
|
from django.utils.encoding import force_str
|
||||||
|
|
|
@ -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',
|
||||||
|
]
|
|
@ -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
|
|
@ -0,0 +1,11 @@
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.http import Http404
|
||||||
|
|
||||||
|
|
||||||
|
class Resolver404(Http404):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class NoReverseMatch(Exception):
|
||||||
|
pass
|
|
@ -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]
|
|
@ -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
|
import types
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.urlresolvers import Resolver404, resolve
|
|
||||||
from django.http import HttpResponse, HttpResponseNotFound
|
from django.http import HttpResponse, HttpResponseNotFound
|
||||||
from django.template import Context, Engine, TemplateDoesNotExist
|
from django.template import Context, Engine, TemplateDoesNotExist
|
||||||
from django.template.defaultfilters import force_escape, pprint
|
from django.template.defaultfilters import force_escape, pprint
|
||||||
|
from django.urls import Resolver404, resolve
|
||||||
from django.utils import lru_cache, six, timezone
|
from django.utils import lru_cache, six, timezone
|
||||||
from django.utils.datastructures import MultiValueDict
|
from django.utils.datastructures import MultiValueDict
|
||||||
from django.utils.encoding import force_bytes, smart_text
|
from django.utils.encoding import force_bytes, smart_text
|
||||||
|
|
|
@ -5,8 +5,8 @@ from functools import update_wrapper
|
||||||
|
|
||||||
from django import http
|
from django import http
|
||||||
from django.core.exceptions import ImproperlyConfigured
|
from django.core.exceptions import ImproperlyConfigured
|
||||||
from django.core.urlresolvers import NoReverseMatch, reverse
|
|
||||||
from django.template.response import TemplateResponse
|
from django.template.response import TemplateResponse
|
||||||
|
from django.urls import NoReverseMatch, reverse
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
from django.utils.decorators import classonlymethod
|
from django.utils.decorators import classonlymethod
|
||||||
|
|
||||||
|
|
|
@ -6,8 +6,8 @@ import os
|
||||||
from django import http
|
from django import http
|
||||||
from django.apps import apps
|
from django.apps import apps
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.urlresolvers import translate_url
|
|
||||||
from django.template import Context, Engine
|
from django.template import Context, Engine
|
||||||
|
from django.urls import translate_url
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
from django.utils._os import upath
|
from django.utils._os import upath
|
||||||
from django.utils.encoding import smart_text
|
from django.utils.encoding import smart_text
|
||||||
|
|
|
@ -262,7 +262,7 @@ already been configured).
|
||||||
So, if there is a module containing some code as follows::
|
So, if there is a module containing some code as follows::
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.urlresolvers import get_callable
|
from django.urls import get_callable
|
||||||
|
|
||||||
default_foo_view = get_callable(settings.FOO_VIEW)
|
default_foo_view = get_callable(settings.FOO_VIEW)
|
||||||
|
|
||||||
|
|
|
@ -128,6 +128,8 @@ details on these changes.
|
||||||
|
|
||||||
* The ``shell --plain`` option will be removed.
|
* The ``shell --plain`` option will be removed.
|
||||||
|
|
||||||
|
* The ``django.core.urlresolvers`` module will be removed.
|
||||||
|
|
||||||
.. _deprecation-removed-in-1.10:
|
.. _deprecation-removed-in-1.10:
|
||||||
|
|
||||||
1.10
|
1.10
|
||||||
|
@ -152,8 +154,7 @@ details on these changes.
|
||||||
* Using an incorrect count of unpacked values in the ``for`` template tag
|
* Using an incorrect count of unpacked values in the ``for`` template tag
|
||||||
will raise an exception rather than fail silently.
|
will raise an exception rather than fail silently.
|
||||||
|
|
||||||
* The ability to :func:`~django.core.urlresolvers.reverse` URLs using a dotted
|
* The ability to reverse URLs using a dotted Python path will be removed.
|
||||||
Python path will be removed.
|
|
||||||
|
|
||||||
* Support for :py:mod:`optparse` will be dropped for custom management commands
|
* Support for :py:mod:`optparse` will be dropped for custom management commands
|
||||||
(replaced by :py:mod:`argparse`).
|
(replaced by :py:mod:`argparse`).
|
||||||
|
|
|
@ -56,7 +56,7 @@ To get from a URL to a view, Django uses what are known as 'URLconfs'. A
|
||||||
URLconf maps URL patterns (described as regular expressions) to views.
|
URLconf maps URL patterns (described as regular expressions) to views.
|
||||||
|
|
||||||
This tutorial provides basic instruction in the use of URLconfs, and you can
|
This tutorial provides basic instruction in the use of URLconfs, and you can
|
||||||
refer to :mod:`django.core.urlresolvers` for more information.
|
refer to :mod:`django.urls` for more information.
|
||||||
|
|
||||||
Writing more views
|
Writing more views
|
||||||
==================
|
==================
|
||||||
|
|
|
@ -71,7 +71,7 @@ create a real version. Add the following to ``polls/views.py``:
|
||||||
|
|
||||||
from django.shortcuts import get_object_or_404, render
|
from django.shortcuts import get_object_or_404, render
|
||||||
from django.http import HttpResponseRedirect, HttpResponse
|
from django.http import HttpResponseRedirect, HttpResponse
|
||||||
from django.core.urlresolvers import reverse
|
from django.urls import reverse
|
||||||
|
|
||||||
from .models import Choice, Question
|
from .models import Choice, Question
|
||||||
# ...
|
# ...
|
||||||
|
@ -124,13 +124,13 @@ This code includes a few things we haven't covered yet in this tutorial:
|
||||||
POST data. This tip isn't specific to Django; it's just good Web
|
POST data. This tip isn't specific to Django; it's just good Web
|
||||||
development practice.
|
development practice.
|
||||||
|
|
||||||
* We are using the :func:`~django.core.urlresolvers.reverse` function in the
|
* We are using the :func:`~django.urls.reverse` function in the
|
||||||
:class:`~django.http.HttpResponseRedirect` constructor in this example.
|
:class:`~django.http.HttpResponseRedirect` constructor in this example.
|
||||||
This function helps avoid having to hardcode a URL in the view function.
|
This function helps avoid having to hardcode a URL in the view function.
|
||||||
It is given the name of the view that we want to pass control to and the
|
It is given the name of the view that we want to pass control to and the
|
||||||
variable portion of the URL pattern that points to that view. In this
|
variable portion of the URL pattern that points to that view. In this
|
||||||
case, using the URLconf we set up in :doc:`Tutorial 3 </intro/tutorial03>`,
|
case, using the URLconf we set up in :doc:`Tutorial 3 </intro/tutorial03>`,
|
||||||
this :func:`~django.core.urlresolvers.reverse` call will return a string like
|
this :func:`~django.urls.reverse` call will return a string like
|
||||||
::
|
::
|
||||||
|
|
||||||
'/polls/3/results/'
|
'/polls/3/results/'
|
||||||
|
@ -264,7 +264,7 @@ views and use Django's generic views instead. To do so, open the
|
||||||
|
|
||||||
from django.shortcuts import get_object_or_404, render
|
from django.shortcuts import get_object_or_404, render
|
||||||
from django.http import HttpResponseRedirect
|
from django.http import HttpResponseRedirect
|
||||||
from django.core.urlresolvers import reverse
|
from django.urls import reverse
|
||||||
from django.views import generic
|
from django.views import generic
|
||||||
|
|
||||||
from .models import Choice, Question
|
from .models import Choice, Question
|
||||||
|
|
|
@ -362,7 +362,7 @@ With that ready, we can ask the client to do some work for us::
|
||||||
404
|
404
|
||||||
>>> # on the other hand we should expect to find something at '/polls/'
|
>>> # on the other hand we should expect to find something at '/polls/'
|
||||||
>>> # we'll use 'reverse()' rather than a hardcoded URL
|
>>> # we'll use 'reverse()' rather than a hardcoded URL
|
||||||
>>> from django.core.urlresolvers import reverse
|
>>> from django.urls import reverse
|
||||||
>>> response = client.get(reverse('polls:index'))
|
>>> response = client.get(reverse('polls:index'))
|
||||||
>>> response.status_code
|
>>> response.status_code
|
||||||
200
|
200
|
||||||
|
@ -447,7 +447,7 @@ Add the following to ``polls/tests.py``:
|
||||||
.. snippet::
|
.. snippet::
|
||||||
:filename: polls/tests.py
|
:filename: polls/tests.py
|
||||||
|
|
||||||
from django.core.urlresolvers import reverse
|
from django.urls import reverse
|
||||||
|
|
||||||
and we'll create a shortcut function to create questions as well as a new test
|
and we'll create a shortcut function to create questions as well as a new test
|
||||||
class:
|
class:
|
||||||
|
|
|
@ -13,7 +13,7 @@ views for displaying drilldown pages for date-based data.
|
||||||
defined as follows in ``myapp/models.py``::
|
defined as follows in ``myapp/models.py``::
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.core.urlresolvers import reverse
|
from django.urls import reverse
|
||||||
|
|
||||||
class Article(models.Model):
|
class Article(models.Model):
|
||||||
title = models.CharField(max_length=200)
|
title = models.CharField(max_length=200)
|
||||||
|
|
|
@ -15,7 +15,7 @@ editing content:
|
||||||
Some of the examples on this page assume that an ``Author`` model has been
|
Some of the examples on this page assume that an ``Author`` model has been
|
||||||
defined as follows in ``myapp/models.py``::
|
defined as follows in ``myapp/models.py``::
|
||||||
|
|
||||||
from django.core.urlresolvers import reverse
|
from django.urls import reverse
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
|
||||||
class Author(models.Model):
|
class Author(models.Model):
|
||||||
|
@ -227,7 +227,7 @@ DeleteView
|
||||||
**Example myapp/views.py**::
|
**Example myapp/views.py**::
|
||||||
|
|
||||||
from django.views.generic.edit import DeleteView
|
from django.views.generic.edit import DeleteView
|
||||||
from django.core.urlresolvers import reverse_lazy
|
from django.urls import reverse_lazy
|
||||||
from myapp.models import Author
|
from myapp.models import Author
|
||||||
|
|
||||||
class AuthorDelete(DeleteView):
|
class AuthorDelete(DeleteView):
|
||||||
|
|
|
@ -1252,7 +1252,7 @@ subclass::
|
||||||
For example::
|
For example::
|
||||||
|
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from django.core.urlresolvers import reverse
|
from django.urls import reverse
|
||||||
|
|
||||||
class PersonAdmin(admin.ModelAdmin):
|
class PersonAdmin(admin.ModelAdmin):
|
||||||
def view_on_site(self, obj):
|
def view_on_site(self, obj):
|
||||||
|
@ -2883,9 +2883,9 @@ So - if you wanted to get a reference to the Change view for a particular
|
||||||
``Choice`` object (from the polls application) in the default admin, you would
|
``Choice`` object (from the polls application) in the default admin, you would
|
||||||
call::
|
call::
|
||||||
|
|
||||||
>>> from django.core import urlresolvers
|
>>> from django.urls import reverse
|
||||||
>>> c = Choice.objects.get(...)
|
>>> c = Choice.objects.get(...)
|
||||||
>>> change_url = urlresolvers.reverse('admin:polls_choice_change', args=(c.id,))
|
>>> change_url = reverse('admin:polls_choice_change', args=(c.id,))
|
||||||
|
|
||||||
This will find the first registered instance of the admin application
|
This will find the first registered instance of the admin application
|
||||||
(whatever the instance name), and resolve to the view for changing
|
(whatever the instance name), and resolve to the view for changing
|
||||||
|
@ -2896,8 +2896,7 @@ that instance as a ``current_app`` hint to the reverse call. For example,
|
||||||
if you specifically wanted the admin view from the admin instance named
|
if you specifically wanted the admin view from the admin instance named
|
||||||
``custom``, you would need to call::
|
``custom``, you would need to call::
|
||||||
|
|
||||||
>>> change_url = urlresolvers.reverse('admin:polls_choice_change',
|
>>> change_url = reverse('admin:polls_choice_change', args=(c.id,), current_app='custom')
|
||||||
... args=(c.id,), current_app='custom')
|
|
||||||
|
|
||||||
For more details, see the documentation on :ref:`reversing namespaced URLs
|
For more details, see the documentation on :ref:`reversing namespaced URLs
|
||||||
<topics-http-reversing-url-namespaces>`.
|
<topics-http-reversing-url-namespaces>`.
|
||||||
|
|
|
@ -300,13 +300,12 @@ Sitemap for static views
|
||||||
|
|
||||||
Often you want the search engine crawlers to index views which are neither
|
Often you want the search engine crawlers to index views which are neither
|
||||||
object detail pages nor flatpages. The solution is to explicitly list URL
|
object detail pages nor flatpages. The solution is to explicitly list URL
|
||||||
names for these views in ``items`` and call
|
names for these views in ``items`` and call :func:`~django.urls.reverse` in
|
||||||
:func:`~django.core.urlresolvers.reverse` in the ``location`` method of
|
the ``location`` method of the sitemap. For example::
|
||||||
the sitemap. For example::
|
|
||||||
|
|
||||||
# sitemaps.py
|
# sitemaps.py
|
||||||
from django.contrib import sitemaps
|
from django.contrib import sitemaps
|
||||||
from django.core.urlresolvers import reverse
|
from django.urls import reverse
|
||||||
|
|
||||||
class StaticViewSitemap(sitemaps.Sitemap):
|
class StaticViewSitemap(sitemaps.Sitemap):
|
||||||
priority = 0.5
|
priority = 0.5
|
||||||
|
|
|
@ -53,7 +53,7 @@ This simple example, taken from a hypothetical police beat news site describes
|
||||||
a feed of the latest five news items::
|
a feed of the latest five news items::
|
||||||
|
|
||||||
from django.contrib.syndication.views import Feed
|
from django.contrib.syndication.views import Feed
|
||||||
from django.core.urlresolvers import reverse
|
from django.urls import reverse
|
||||||
from policebeat.models import NewsItem
|
from policebeat.models import NewsItem
|
||||||
|
|
||||||
class LatestEntriesFeed(Feed):
|
class LatestEntriesFeed(Feed):
|
||||||
|
|
|
@ -84,7 +84,7 @@ Django core exception classes are defined in ``django.core.exceptions``.
|
||||||
.. exception:: ViewDoesNotExist
|
.. exception:: ViewDoesNotExist
|
||||||
|
|
||||||
The :exc:`ViewDoesNotExist` exception is raised by
|
The :exc:`ViewDoesNotExist` exception is raised by
|
||||||
:mod:`django.core.urlresolvers` when a requested view does not exist.
|
:mod:`django.urls` when a requested view does not exist.
|
||||||
|
|
||||||
``MiddlewareNotUsed``
|
``MiddlewareNotUsed``
|
||||||
---------------------
|
---------------------
|
||||||
|
@ -142,12 +142,18 @@ or model are classified as ``NON_FIELD_ERRORS``. This constant is used
|
||||||
as a key in dictionaries that otherwise map fields to their respective
|
as a key in dictionaries that otherwise map fields to their respective
|
||||||
list of errors.
|
list of errors.
|
||||||
|
|
||||||
.. currentmodule:: django.core.urlresolvers
|
.. currentmodule:: django.urls
|
||||||
|
|
||||||
URL Resolver exceptions
|
URL Resolver exceptions
|
||||||
=======================
|
=======================
|
||||||
|
|
||||||
URL Resolver exceptions are defined in ``django.core.urlresolvers``.
|
URL Resolver exceptions are defined in ``django.urls``.
|
||||||
|
|
||||||
|
.. deprecated:: 1.10
|
||||||
|
|
||||||
|
In older versions, these exceptions are located in
|
||||||
|
``django.core.urlresolvers``. Importing from the old location will continue
|
||||||
|
to work until Django 2.0.
|
||||||
|
|
||||||
``Resolver404``
|
``Resolver404``
|
||||||
---------------
|
---------------
|
||||||
|
@ -155,18 +161,17 @@ URL Resolver exceptions are defined in ``django.core.urlresolvers``.
|
||||||
.. exception:: Resolver404
|
.. exception:: Resolver404
|
||||||
|
|
||||||
The :exc:`Resolver404` exception is raised by
|
The :exc:`Resolver404` exception is raised by
|
||||||
:func:`django.core.urlresolvers.resolve()` if the path passed to
|
:func:`~django.urls.resolve()` if the path passed to ``resolve()`` doesn't
|
||||||
``resolve()`` doesn't map to a view. It's a subclass of
|
map to a view. It's a subclass of :class:`django.http.Http404`.
|
||||||
:class:`django.http.Http404`.
|
|
||||||
|
|
||||||
``NoReverseMatch``
|
``NoReverseMatch``
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
.. exception:: NoReverseMatch
|
.. exception:: NoReverseMatch
|
||||||
|
|
||||||
The :exc:`NoReverseMatch` exception is raised by
|
The :exc:`NoReverseMatch` exception is raised by :mod:`django.urls` when a
|
||||||
:mod:`django.core.urlresolvers` when a matching URL in your URLconf
|
matching URL in your URLconf cannot be identified based on the parameters
|
||||||
cannot be identified based on the parameters supplied.
|
supplied.
|
||||||
|
|
||||||
.. currentmodule:: django.db
|
.. currentmodule:: django.db
|
||||||
|
|
||||||
|
|
|
@ -672,14 +672,14 @@ For example::
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return "/people/%i/" % self.id
|
return "/people/%i/" % self.id
|
||||||
|
|
||||||
(Whilst this code is correct and simple, it may not be the most portable way to
|
While this code is correct and simple, it may not be the most portable way to
|
||||||
write this kind of method. The :func:`~django.core.urlresolvers.reverse`
|
to write this kind of method. The :func:`~django.urls.reverse` function is
|
||||||
function is usually the best approach.)
|
usually the best approach.
|
||||||
|
|
||||||
For example::
|
For example::
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
from django.core.urlresolvers import reverse
|
from django.urls import reverse
|
||||||
return reverse('people.views.details', args=[str(self.id)])
|
return reverse('people.views.details', args=[str(self.id)])
|
||||||
|
|
||||||
One place Django uses ``get_absolute_url()`` is in the admin app. If an object
|
One place Django uses ``get_absolute_url()`` is in the admin app. If an object
|
||||||
|
|
|
@ -160,11 +160,11 @@ All attributes should be considered read-only, unless stated otherwise.
|
||||||
|
|
||||||
.. attribute:: HttpRequest.resolver_match
|
.. attribute:: HttpRequest.resolver_match
|
||||||
|
|
||||||
An instance of :class:`~django.core.urlresolvers.ResolverMatch` representing
|
An instance of :class:`~django.urls.ResolverMatch` representing the
|
||||||
the resolved url. This attribute is only set after url resolving took place,
|
resolved URL. This attribute is only set after URL resolving took place,
|
||||||
which means it's available in all views but not in middleware methods which
|
which means it's available in all views but not in middleware methods
|
||||||
are executed before url resolving takes place (like ``process_request``, you
|
which are executed before URL resolving takes place (like
|
||||||
can use ``process_view`` instead).
|
``process_request()``, you can use ``process_view()`` instead).
|
||||||
|
|
||||||
Attributes set by application code
|
Attributes set by application code
|
||||||
----------------------------------
|
----------------------------------
|
||||||
|
@ -175,7 +175,7 @@ application.
|
||||||
.. attribute:: HttpRequest.current_app
|
.. attribute:: HttpRequest.current_app
|
||||||
|
|
||||||
The :ttag:`url` template tag will use its value as the ``current_app``
|
The :ttag:`url` template tag will use its value as the ``current_app``
|
||||||
argument to :func:`~django.core.urlresolvers.reverse()`.
|
argument to :func:`~django.urls.reverse()`.
|
||||||
|
|
||||||
.. attribute:: HttpRequest.urlconf
|
.. attribute:: HttpRequest.urlconf
|
||||||
|
|
||||||
|
|
|
@ -1024,8 +1024,8 @@ such as this:
|
||||||
The template tag will output the string ``/clients/client/123/``.
|
The template tag will output the string ``/clients/client/123/``.
|
||||||
|
|
||||||
Note that if the URL you're reversing doesn't exist, you'll get an
|
Note that if the URL you're reversing doesn't exist, you'll get an
|
||||||
:exc:`~django.core.urlresolvers.NoReverseMatch` exception raised, which will
|
:exc:`~django.urls.NoReverseMatch` exception raised, which will cause your
|
||||||
cause your site to display an error page.
|
site to display an error page.
|
||||||
|
|
||||||
If you'd like to retrieve a URL without displaying it, you can use a slightly
|
If you'd like to retrieve a URL without displaying it, you can use a slightly
|
||||||
different call::
|
different call::
|
||||||
|
|
|
@ -290,8 +290,8 @@ Taking care in ``get_absolute_url()``
|
||||||
|
|
||||||
URLs can only contain ASCII characters. If you're constructing a URL from
|
URLs can only contain ASCII characters. If you're constructing a URL from
|
||||||
pieces of data that might be non-ASCII, be careful to encode the results in a
|
pieces of data that might be non-ASCII, be careful to encode the results in a
|
||||||
way that is suitable for a URL. The :func:`~django.core.urlresolvers.reverse`
|
way that is suitable for a URL. The :func:`~django.urls.reverse` function
|
||||||
function handles this for you automatically.
|
handles this for you automatically.
|
||||||
|
|
||||||
If you're constructing a URL manually (i.e., *not* using the ``reverse()``
|
If you're constructing a URL manually (i.e., *not* using the ``reverse()``
|
||||||
function), you'll need to take care of the encoding yourself. In this case,
|
function), you'll need to take care of the encoding yourself. In this case,
|
||||||
|
|
|
@ -1,8 +1,14 @@
|
||||||
==============================================
|
=================================
|
||||||
``django.core.urlresolvers`` utility functions
|
``django.urls`` utility functions
|
||||||
==============================================
|
=================================
|
||||||
|
|
||||||
.. module:: django.core.urlresolvers
|
.. module:: django.urls
|
||||||
|
|
||||||
|
.. deprecated:: 1.10
|
||||||
|
|
||||||
|
In older versions, these functions are located in
|
||||||
|
``django.core.urlresolvers``. Importing from the old location will continue
|
||||||
|
to work until Django 2.0.
|
||||||
|
|
||||||
reverse()
|
reverse()
|
||||||
---------
|
---------
|
||||||
|
@ -31,7 +37,7 @@ you can use any of the following to reverse the URL::
|
||||||
|
|
||||||
If the URL accepts arguments, you may pass them in ``args``. For example::
|
If the URL accepts arguments, you may pass them in ``args``. For example::
|
||||||
|
|
||||||
from django.core.urlresolvers import reverse
|
from django.urls import reverse
|
||||||
|
|
||||||
def myview(request):
|
def myview(request):
|
||||||
return HttpResponseRedirect(reverse('arch-summary', args=[1945]))
|
return HttpResponseRedirect(reverse('arch-summary', args=[1945]))
|
||||||
|
@ -44,7 +50,7 @@ You can also pass ``kwargs`` instead of ``args``. For example::
|
||||||
``args`` and ``kwargs`` cannot be passed to ``reverse()`` at the same time.
|
``args`` and ``kwargs`` cannot be passed to ``reverse()`` at the same time.
|
||||||
|
|
||||||
If no match can be made, ``reverse()`` raises a
|
If no match can be made, ``reverse()`` raises a
|
||||||
:class:`~django.core.urlresolvers.NoReverseMatch` exception.
|
:class:`~django.urls.NoReverseMatch` exception.
|
||||||
|
|
||||||
The ``reverse()`` function can reverse a large variety of regular expression
|
The ``reverse()`` function can reverse a large variety of regular expression
|
||||||
patterns for URLs, but not every possible one. The main restriction at the
|
patterns for URLs, but not every possible one. The main restriction at the
|
||||||
|
@ -103,13 +109,12 @@ corresponding view functions. It has the following signature:
|
||||||
.. function:: resolve(path, urlconf=None)
|
.. function:: resolve(path, urlconf=None)
|
||||||
|
|
||||||
``path`` is the URL path you want to resolve. As with
|
``path`` is the URL path you want to resolve. As with
|
||||||
:func:`~django.core.urlresolvers.reverse`, you don't need to
|
:func:`~django.urls.reverse`, you don't need to worry about the ``urlconf``
|
||||||
worry about the ``urlconf`` parameter. The function returns a
|
parameter. The function returns a :class:`ResolverMatch` object that allows you
|
||||||
:class:`ResolverMatch` object that allows you
|
to access various metadata about the resolved URL.
|
||||||
to access various meta-data about the resolved URL.
|
|
||||||
|
|
||||||
If the URL does not resolve, the function raises a
|
If the URL does not resolve, the function raises a
|
||||||
:exc:`~django.core.urlresolvers.Resolver404` exception (a subclass of
|
:exc:`~django.urls.Resolver404` exception (a subclass of
|
||||||
:class:`~django.http.Http404`) .
|
:class:`~django.http.Http404`) .
|
||||||
|
|
||||||
.. class:: ResolverMatch
|
.. class:: ResolverMatch
|
||||||
|
@ -175,10 +180,10 @@ A :class:`ResolverMatch` object can also be assigned to a triple::
|
||||||
|
|
||||||
func, args, kwargs = resolve('/some/path/')
|
func, args, kwargs = resolve('/some/path/')
|
||||||
|
|
||||||
One possible use of :func:`~django.core.urlresolvers.resolve` would be to test
|
One possible use of :func:`~django.urls.resolve` would be to test whether a
|
||||||
whether a view would raise a ``Http404`` error before redirecting to it::
|
view would raise a ``Http404`` error before redirecting to it::
|
||||||
|
|
||||||
from django.core.urlresolvers import resolve
|
from django.urls import resolve
|
||||||
from django.http import HttpResponseRedirect, Http404
|
from django.http import HttpResponseRedirect, Http404
|
||||||
from django.utils.six.moves.urllib.parse import urlparse
|
from django.utils.six.moves.urllib.parse import urlparse
|
||||||
|
|
||||||
|
@ -202,12 +207,11 @@ get_script_prefix()
|
||||||
|
|
||||||
.. function:: get_script_prefix()
|
.. function:: get_script_prefix()
|
||||||
|
|
||||||
Normally, you should always use :func:`~django.core.urlresolvers.reverse` to
|
Normally, you should always use :func:`~django.urls.reverse` to define URLs
|
||||||
define URLs within your application. However, if your application constructs
|
within your application. However, if your application constructs part of the
|
||||||
part of the URL hierarchy itself, you may occasionally need to generate URLs.
|
URL hierarchy itself, you may occasionally need to generate URLs. In that
|
||||||
In that case, you need to be able to find the base URL of the Django project
|
case, you need to be able to find the base URL of the Django project within
|
||||||
within its Web server (normally, :func:`~django.core.urlresolvers.reverse`
|
its Web server (normally, :func:`~django.urls.reverse` takes care of this for
|
||||||
takes care of this for you). In that case, you can call
|
you). In that case, you can call ``get_script_prefix()``, which will return
|
||||||
``get_script_prefix()``, which will return the script prefix portion of the URL
|
the script prefix portion of the URL for your Django project. If your Django
|
||||||
for your Django project. If your Django project is at the root of its web
|
project is at the root of its web server, this is always ``"/"``.
|
||||||
server, this is always ``"/"``.
|
|
||||||
|
|
|
@ -380,11 +380,11 @@ Other new features and changes introduced since Django 1.0 include:
|
||||||
order to allow fine-grained control of when and where the CSRF processing
|
order to allow fine-grained control of when and where the CSRF processing
|
||||||
takes place.
|
takes place.
|
||||||
|
|
||||||
* :func:`~django.core.urlresolvers.reverse` and code which uses it (e.g., the
|
* ``reverse()`` and code which uses it (e.g., the ``{% url %}`` template tag)
|
||||||
``{% url %}`` template tag) now works with URLs in Django's administrative
|
now works with URLs in Django's administrative site, provided that the admin
|
||||||
site, provided that the admin URLs are set up via ``include(admin.site.urls)``
|
URLs are set up via ``include(admin.site.urls)`` (sending admin requests to
|
||||||
(sending admin requests to the ``admin.site.root`` view still works, but URLs
|
the ``admin.site.root`` view still works, but URLs in the admin will not be
|
||||||
in the admin will not be "reversible" when configured this way).
|
"reversible" when configured this way).
|
||||||
|
|
||||||
* The ``include()`` function in Django URLconf modules can now accept sequences
|
* The ``include()`` function in Django URLconf modules can now accept sequences
|
||||||
of URL patterns (generated by ``patterns()``) in addition to module names.
|
of URL patterns (generated by ``patterns()``) in addition to module names.
|
||||||
|
|
|
@ -460,6 +460,9 @@ Miscellaneous
|
||||||
* The ``shell --plain`` option is deprecated in favor of ``-i python`` or
|
* The ``shell --plain`` option is deprecated in favor of ``-i python`` or
|
||||||
``--interface python``.
|
``--interface python``.
|
||||||
|
|
||||||
|
* Importing from the ``django.core.urlresolvers`` module is deprecated in
|
||||||
|
favor of its new location, :mod:`django.urls`.
|
||||||
|
|
||||||
.. _removed-features-1.10:
|
.. _removed-features-1.10:
|
||||||
|
|
||||||
Features removed in 1.10
|
Features removed in 1.10
|
||||||
|
@ -485,8 +488,8 @@ removed in Django 1.10 (please see the :ref:`deprecation timeline
|
||||||
* Using an incorrect count of unpacked values in the ``for`` template tag
|
* Using an incorrect count of unpacked values in the ``for`` template tag
|
||||||
raises an exception rather than failing silently.
|
raises an exception rather than failing silently.
|
||||||
|
|
||||||
* The ability to :func:`~django.core.urlresolvers.reverse` URLs using a dotted
|
* The ability to :func:`~django.urls.reverse` URLs using a dotted Python path
|
||||||
Python path is removed.
|
is removed.
|
||||||
|
|
||||||
* Support for ``optparse`` is dropped for custom management commands.
|
* Support for ``optparse`` is dropped for custom management commands.
|
||||||
|
|
||||||
|
|
|
@ -16,14 +16,12 @@ Django's URL handling is based on a mapping of regex patterns
|
||||||
consists of matching a requested URL against those patterns to
|
consists of matching a requested URL against those patterns to
|
||||||
determine the appropriate view to invoke.
|
determine the appropriate view to invoke.
|
||||||
|
|
||||||
Django also provides a convenience function --
|
Django also provides a convenience function -- ``reverse()`` -- which performs
|
||||||
:func:`~django.core.urlresolvers.reverse` -- which performs this process
|
this process in the opposite direction. The ``reverse()`` function takes
|
||||||
in the opposite direction. The ``reverse()`` function takes
|
information about a view and returns a URL which would invoke that view. Use
|
||||||
information about a view and returns a URL which would invoke that
|
of ``reverse()`` is encouraged for application developers, as the output of
|
||||||
view. Use of ``reverse()`` is encouraged for application developers,
|
``reverse()`` is always based on the current URL patterns, meaning developers
|
||||||
as the output of ``reverse()`` is always based on the current URL
|
do not need to change other code when making changes to URLs.
|
||||||
patterns, meaning developers do not need to change other code when
|
|
||||||
making changes to URLs.
|
|
||||||
|
|
||||||
One argument signature for ``reverse()`` is to pass a dotted Python
|
One argument signature for ``reverse()`` is to pass a dotted Python
|
||||||
path to the desired view. In this situation, Django will import the
|
path to the desired view. In this situation, Django will import the
|
||||||
|
|
|
@ -9,6 +9,5 @@ Django 1.4.12 fixes a regression in the 1.4.11 security release.
|
||||||
Bugfixes
|
Bugfixes
|
||||||
========
|
========
|
||||||
|
|
||||||
* Restored the ability to :meth:`~django.core.urlresolvers.reverse` views
|
* Restored the ability to ``reverse()`` views created using
|
||||||
created using :func:`functools.partial()`
|
:func:`functools.partial()` (:ticket:`22486`).
|
||||||
(:ticket:`22486`)
|
|
||||||
|
|
|
@ -6,8 +6,8 @@ Django 1.4.14 release notes
|
||||||
|
|
||||||
Django 1.4.14 fixes several security issues in 1.4.13.
|
Django 1.4.14 fixes several security issues in 1.4.13.
|
||||||
|
|
||||||
:func:`~django.core.urlresolvers.reverse()` could generate URLs pointing to other hosts
|
``reverse()`` could generate URLs pointing to other hosts
|
||||||
=======================================================================================
|
=========================================================
|
||||||
|
|
||||||
In certain situations, URL reversing could generate scheme-relative URLs (URLs
|
In certain situations, URL reversing could generate scheme-relative URLs (URLs
|
||||||
starting with two slashes), which could unexpectedly redirect a user to a
|
starting with two slashes), which could unexpectedly redirect a user to a
|
||||||
|
|
|
@ -371,8 +371,8 @@ Django 1.4 to store the wizard's state in the user's cookies.
|
||||||
``reverse_lazy``
|
``reverse_lazy``
|
||||||
~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
A lazily evaluated version of :func:`django.core.urlresolvers.reverse` was
|
A lazily evaluated version of ``reverse()`` was added to allow using URL
|
||||||
added to allow using URL reversals before the project's URLconf gets loaded.
|
reversals before the project's URLconf gets loaded.
|
||||||
|
|
||||||
Translating URL patterns
|
Translating URL patterns
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
|
@ -15,14 +15,12 @@ Django's URL handling is based on a mapping of regex patterns
|
||||||
consists of matching a requested URL against those patterns to
|
consists of matching a requested URL against those patterns to
|
||||||
determine the appropriate view to invoke.
|
determine the appropriate view to invoke.
|
||||||
|
|
||||||
Django also provides a convenience function --
|
Django also provides a convenience function -- ``reverse()`` -- which performs
|
||||||
:func:`~django.core.urlresolvers.reverse` -- which performs this process
|
this process in the opposite direction. The ``reverse()`` function takes
|
||||||
in the opposite direction. The ``reverse()`` function takes
|
information about a view and returns a URL which would invoke that view. Use
|
||||||
information about a view and returns a URL which would invoke that
|
of ``reverse()`` is encouraged for application developers, as the output of
|
||||||
view. Use of ``reverse()`` is encouraged for application developers,
|
``reverse()`` is always based on the current URL patterns, meaning developers
|
||||||
as the output of ``reverse()`` is always based on the current URL
|
do not need to change other code when making changes to URLs.
|
||||||
patterns, meaning developers do not need to change other code when
|
|
||||||
making changes to URLs.
|
|
||||||
|
|
||||||
One argument signature for ``reverse()`` is to pass a dotted Python
|
One argument signature for ``reverse()`` is to pass a dotted Python
|
||||||
path to the desired view. In this situation, Django will import the
|
path to the desired view. In this situation, Django will import the
|
||||||
|
|
|
@ -9,5 +9,5 @@ Django 1.5.7 fixes a regression in the 1.5.6 security release.
|
||||||
Bugfixes
|
Bugfixes
|
||||||
========
|
========
|
||||||
|
|
||||||
* Restored the ability to :meth:`~django.core.urlresolvers.reverse` views
|
* Restored the ability to ``reverse()`` views created using
|
||||||
created using :func:`functools.partial()` (:ticket:`22486`).
|
:func:`functools.partial()` (:ticket:`22486`).
|
||||||
|
|
|
@ -6,8 +6,8 @@ Django 1.5.9 release notes
|
||||||
|
|
||||||
Django 1.5.9 fixes several security issues in 1.5.8.
|
Django 1.5.9 fixes several security issues in 1.5.8.
|
||||||
|
|
||||||
:func:`~django.core.urlresolvers.reverse()` could generate URLs pointing to other hosts
|
``reverse()`` could generate URLs pointing to other hosts
|
||||||
=======================================================================================
|
=========================================================
|
||||||
|
|
||||||
In certain situations, URL reversing could generate scheme-relative URLs (URLs
|
In certain situations, URL reversing could generate scheme-relative URLs (URLs
|
||||||
starting with two slashes), which could unexpectedly redirect a user to a
|
starting with two slashes), which could unexpectedly redirect a user to a
|
||||||
|
|
|
@ -293,8 +293,8 @@ Django 1.5 also includes several smaller improvements worth noting:
|
||||||
objects fetched into memory. See :meth:`QuerySet.delete()
|
objects fetched into memory. See :meth:`QuerySet.delete()
|
||||||
<django.db.models.query.QuerySet.delete>` for details.
|
<django.db.models.query.QuerySet.delete>` for details.
|
||||||
|
|
||||||
* An instance of :class:`~django.core.urlresolvers.ResolverMatch` is stored on
|
* An instance of ``ResolverMatch`` is stored on the request as
|
||||||
the request as ``resolver_match``.
|
``resolver_match``.
|
||||||
|
|
||||||
* By default, all logging messages reaching the ``django`` logger when
|
* By default, all logging messages reaching the ``django`` logger when
|
||||||
:setting:`DEBUG` is ``True`` are sent to the console (unless you redefine the
|
:setting:`DEBUG` is ``True`` are sent to the console (unless you redefine the
|
||||||
|
|
|
@ -15,14 +15,12 @@ Django's URL handling is based on a mapping of regex patterns
|
||||||
consists of matching a requested URL against those patterns to
|
consists of matching a requested URL against those patterns to
|
||||||
determine the appropriate view to invoke.
|
determine the appropriate view to invoke.
|
||||||
|
|
||||||
Django also provides a convenience function --
|
Django also provides a convenience function -- ``reverse()`` -- which performs
|
||||||
:func:`~django.core.urlresolvers.reverse` -- which performs this process
|
this process in the opposite direction. The ``reverse()`` function takes
|
||||||
in the opposite direction. The ``reverse()`` function takes
|
information about a view and returns a URL which would invoke that view. Use
|
||||||
information about a view and returns a URL which would invoke that
|
of ``reverse()`` is encouraged for application developers, as the output of
|
||||||
view. Use of ``reverse()`` is encouraged for application developers,
|
``reverse()`` is always based on the current URL patterns, meaning developers
|
||||||
as the output of ``reverse()`` is always based on the current URL
|
do not need to change other code when making changes to URLs.
|
||||||
patterns, meaning developers do not need to change other code when
|
|
||||||
making changes to URLs.
|
|
||||||
|
|
||||||
One argument signature for ``reverse()`` is to pass a dotted Python
|
One argument signature for ``reverse()`` is to pass a dotted Python
|
||||||
path to the desired view. In this situation, Django will import the
|
path to the desired view. In this situation, Django will import the
|
||||||
|
|
|
@ -13,10 +13,8 @@ Bugfixes
|
||||||
cookie format of Django 1.4 and earlier to facilitate upgrading to 1.6 from
|
cookie format of Django 1.4 and earlier to facilitate upgrading to 1.6 from
|
||||||
1.4 (:ticket:`22426`).
|
1.4 (:ticket:`22426`).
|
||||||
|
|
||||||
* Restored the ability to :meth:`~django.core.urlresolvers.reverse` views
|
* Restored the ability to ``reverse()`` views created using
|
||||||
created using :func:`functools.partial()`
|
:func:`functools.partial()` (:ticket:`22486`).
|
||||||
(:ticket:`22486`).
|
|
||||||
|
|
||||||
* Fixed the ``object_id`` of the ``LogEntry`` that's created after a user
|
* Fixed the ``object_id`` of the ``LogEntry`` that's created after a user
|
||||||
password change in the admin
|
password change in the admin (:ticket:`22515`).
|
||||||
(:ticket:`22515`).
|
|
||||||
|
|
|
@ -6,8 +6,8 @@ Django 1.6.6 release notes
|
||||||
|
|
||||||
Django 1.6.6 fixes several security issues and bugs in 1.6.5.
|
Django 1.6.6 fixes several security issues and bugs in 1.6.5.
|
||||||
|
|
||||||
:func:`~django.core.urlresolvers.reverse()` could generate URLs pointing to other hosts
|
``reverse()`` could generate URLs pointing to other hosts
|
||||||
=======================================================================================
|
=========================================================
|
||||||
|
|
||||||
In certain situations, URL reversing could generate scheme-relative URLs (URLs
|
In certain situations, URL reversing could generate scheme-relative URLs (URLs
|
||||||
starting with two slashes), which could unexpectedly redirect a user to a
|
starting with two slashes), which could unexpectedly redirect a user to a
|
||||||
|
|
|
@ -583,16 +583,17 @@ be at the end of a line. If they are not, the comments are ignored and
|
||||||
{{ title }}{# Translators: Extracted and associated with 'Welcome' below #}
|
{{ title }}{# Translators: Extracted and associated with 'Welcome' below #}
|
||||||
<h1>{% trans "Welcome" %}</h1>
|
<h1>{% trans "Welcome" %}</h1>
|
||||||
|
|
||||||
Quoting in :func:`~django.core.urlresolvers.reverse`
|
Quoting in ``reverse()``
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
When reversing URLs, Django didn't apply :func:`~django.utils.http.urlquote`
|
When reversing URLs, Django didn't apply :func:`~django.utils.http.urlquote`
|
||||||
to arguments before interpolating them in URL patterns. This bug is fixed in
|
to arguments before interpolating them in URL patterns. This bug is fixed in
|
||||||
Django 1.6. If you worked around this bug by applying URL quoting before
|
Django 1.6. If you worked around this bug by applying URL quoting before
|
||||||
passing arguments to :func:`~django.core.urlresolvers.reverse`, this may
|
passing arguments to ``reverse()``, this may result in double-quoting. If this
|
||||||
result in double-quoting. If this happens, simply remove the URL quoting from
|
happens, simply remove the URL quoting from your code. You will also have to
|
||||||
your code. You will also have to replace special characters in URLs used in
|
replace special characters in URLs used in
|
||||||
:func:`~django.test.SimpleTestCase.assertRedirects` with their encoded versions.
|
:func:`~django.test.SimpleTestCase.assertRedirects` with their encoded
|
||||||
|
versions.
|
||||||
|
|
||||||
Storage of IP addresses in the comments app
|
Storage of IP addresses in the comments app
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
@ -902,12 +903,12 @@ Miscellaneous
|
||||||
stored as ``null``. Previously, storing a ``blank`` value in a field which
|
stored as ``null``. Previously, storing a ``blank`` value in a field which
|
||||||
did not allow ``null`` would cause a database exception at runtime.
|
did not allow ``null`` would cause a database exception at runtime.
|
||||||
|
|
||||||
* If a :class:`~django.core.urlresolvers.NoReverseMatch` exception is raised
|
* If a ``NoReverseMatch`` exception is raised from a method when rendering a
|
||||||
from a method when rendering a template, it is not silenced. For example,
|
template, it is not silenced. For example, ``{{ obj.view_href }}`` will
|
||||||
``{{ obj.view_href }}`` will cause template rendering to fail if
|
cause template rendering to fail if ``view_href()`` raises
|
||||||
``view_href()`` raises ``NoReverseMatch``. There is no change to the
|
``NoReverseMatch``. There is no change to the :ttag:`{% url %}<url>` tag, it
|
||||||
:ttag:`{% url %}<url>` tag, it causes template rendering to fail like always
|
causes template rendering to fail like always when ``NoReverseMatch`` is
|
||||||
when ``NoReverseMatch`` is raised.
|
raised.
|
||||||
|
|
||||||
* :meth:`django.test.Client.logout` now calls
|
* :meth:`django.test.Client.logout` now calls
|
||||||
:meth:`django.contrib.auth.logout` which will send the
|
:meth:`django.contrib.auth.logout` which will send the
|
||||||
|
|
|
@ -82,8 +82,7 @@ Bugfixes
|
||||||
(:ticket:`23815`).
|
(:ticket:`23815`).
|
||||||
|
|
||||||
* Fixed a crash in the ``django.contrib.auth.redirect_to_login`` view when
|
* Fixed a crash in the ``django.contrib.auth.redirect_to_login`` view when
|
||||||
passing a :func:`~django.core.urlresolvers.reverse_lazy` result on Python 3
|
passing a ``reverse_lazy()`` result on Python 3 (:ticket:`24097`).
|
||||||
(:ticket:`24097`).
|
|
||||||
|
|
||||||
* Added correct formats for Greek (``el``) (:ticket:`23967`).
|
* Added correct formats for Greek (``el``) (:ticket:`23967`).
|
||||||
|
|
||||||
|
|
|
@ -1112,9 +1112,8 @@ Miscellaneous
|
||||||
* The default max size of the Oracle test tablespace has increased from 300M
|
* The default max size of the Oracle test tablespace has increased from 300M
|
||||||
(or 200M, before 1.7.2) to 500M.
|
(or 200M, before 1.7.2) to 500M.
|
||||||
|
|
||||||
* :func:`~django.core.urlresolvers.reverse` and
|
* ``reverse()`` and ``reverse_lazy()`` now return Unicode strings instead of
|
||||||
:func:`~django.core.urlresolvers.reverse_lazy` now return Unicode strings
|
byte strings.
|
||||||
instead of byte strings.
|
|
||||||
|
|
||||||
* The ``CacheClass`` shim has been removed from all cache backends.
|
* The ``CacheClass`` shim has been removed from all cache backends.
|
||||||
These aliases were provided for backwards compatibility with Django 1.3.
|
These aliases were provided for backwards compatibility with Django 1.3.
|
||||||
|
@ -1334,8 +1333,8 @@ Using an incorrect count of unpacked values in the :ttag:`for` template tag
|
||||||
Using an incorrect count of unpacked values in :ttag:`for` tag will raise an
|
Using an incorrect count of unpacked values in :ttag:`for` tag will raise an
|
||||||
exception rather than fail silently in Django 1.10.
|
exception rather than fail silently in Django 1.10.
|
||||||
|
|
||||||
Passing a dotted path to :func:`~django.core.urlresolvers.reverse()` and :ttag:`url`
|
Passing a dotted path to ``reverse()`` and :ttag:`url`
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
Reversing URLs by Python path is an expensive operation as it causes the
|
Reversing URLs by Python path is an expensive operation as it causes the
|
||||||
path being reversed to be imported. This behavior has also resulted in a
|
path being reversed to be imported. This behavior has also resulted in a
|
||||||
|
|
|
@ -1083,12 +1083,10 @@ Miscellaneous
|
||||||
:attr:`~django.test.SimpleTestCase.allow_database_queries` class attribute
|
:attr:`~django.test.SimpleTestCase.allow_database_queries` class attribute
|
||||||
to ``True`` on your test class.
|
to ``True`` on your test class.
|
||||||
|
|
||||||
* :attr:`ResolverMatch.app_name
|
* ``ResolverMatch.app_name`` was changed to contain the full namespace path in
|
||||||
<django.core.urlresolvers.ResolverMatch.app_name>` was changed to contain
|
the case of nested namespaces. For consistency with
|
||||||
the full namespace path in the case of nested namespaces. For consistency
|
``ResolverMatch.namespace``, the empty value is now an empty string instead
|
||||||
with :attr:`ResolverMatch.namespace
|
of ``None``.
|
||||||
<django.core.urlresolvers.ResolverMatch.namespace>`, the empty value is now
|
|
||||||
an empty string instead of ``None``.
|
|
||||||
|
|
||||||
* For security hardening, session keys must be at least 8 characters.
|
* For security hardening, session keys must be at least 8 characters.
|
||||||
|
|
||||||
|
|
|
@ -98,7 +98,7 @@ First we need to add :meth:`~django.db.models.Model.get_absolute_url()` to our
|
||||||
.. snippet::
|
.. snippet::
|
||||||
:filename: models.py
|
:filename: models.py
|
||||||
|
|
||||||
from django.core.urlresolvers import reverse
|
from django.urls import reverse
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
|
||||||
class Author(models.Model):
|
class Author(models.Model):
|
||||||
|
@ -115,7 +115,7 @@ here; we don't have to write any logic ourselves:
|
||||||
:filename: views.py
|
:filename: views.py
|
||||||
|
|
||||||
from django.views.generic.edit import CreateView, UpdateView, DeleteView
|
from django.views.generic.edit import CreateView, UpdateView, DeleteView
|
||||||
from django.core.urlresolvers import reverse_lazy
|
from django.urls import reverse_lazy
|
||||||
from myapp.models import Author
|
from myapp.models import Author
|
||||||
|
|
||||||
class AuthorCreate(CreateView):
|
class AuthorCreate(CreateView):
|
||||||
|
@ -131,8 +131,8 @@ here; we don't have to write any logic ourselves:
|
||||||
success_url = reverse_lazy('author-list')
|
success_url = reverse_lazy('author-list')
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
We have to use :func:`~django.core.urlresolvers.reverse_lazy` here, not
|
We have to use :func:`~django.urls.reverse_lazy` here, not just
|
||||||
just ``reverse`` as the urls are not loaded when the file is imported.
|
``reverse()`` as the urls are not loaded when the file is imported.
|
||||||
|
|
||||||
The ``fields`` attribute works the same way as the ``fields`` attribute on the
|
The ``fields`` attribute works the same way as the ``fields`` attribute on the
|
||||||
inner ``Meta`` class on :class:`~django.forms.ModelForm`. Unless you define the
|
inner ``Meta`` class on :class:`~django.forms.ModelForm`. Unless you define the
|
||||||
|
|
|
@ -225,7 +225,7 @@ We'll demonstrate this with the ``Author`` model we used in the
|
||||||
:filename: views.py
|
:filename: views.py
|
||||||
|
|
||||||
from django.http import HttpResponseForbidden, HttpResponseRedirect
|
from django.http import HttpResponseForbidden, HttpResponseRedirect
|
||||||
from django.core.urlresolvers import reverse
|
from django.urls import reverse
|
||||||
from django.views.generic import View
|
from django.views.generic import View
|
||||||
from django.views.generic.detail import SingleObjectMixin
|
from django.views.generic.detail import SingleObjectMixin
|
||||||
from books.models import Author
|
from books.models import Author
|
||||||
|
@ -445,7 +445,7 @@ Our new ``AuthorDetail`` looks like this::
|
||||||
|
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.http import HttpResponseForbidden
|
from django.http import HttpResponseForbidden
|
||||||
from django.core.urlresolvers import reverse
|
from django.urls import reverse
|
||||||
from django.views.generic import DetailView
|
from django.views.generic import DetailView
|
||||||
from django.views.generic.edit import FormMixin
|
from django.views.generic.edit import FormMixin
|
||||||
from books.models import Author
|
from books.models import Author
|
||||||
|
@ -541,7 +541,7 @@ can find the author we're talking about, and we have to remember to set
|
||||||
``template_name`` to ensure that form errors will render the same
|
``template_name`` to ensure that form errors will render the same
|
||||||
template as ``AuthorDisplay`` is using on ``GET``::
|
template as ``AuthorDisplay`` is using on ``GET``::
|
||||||
|
|
||||||
from django.core.urlresolvers import reverse
|
from django.urls import reverse
|
||||||
from django.http import HttpResponseForbidden
|
from django.http import HttpResponseForbidden
|
||||||
from django.views.generic import FormView
|
from django.views.generic import FormView
|
||||||
from django.views.generic.detail import SingleObjectMixin
|
from django.views.generic.detail import SingleObjectMixin
|
||||||
|
|
|
@ -103,9 +103,8 @@ This example is equivalent to::
|
||||||
* A model: the model's :meth:`~django.db.models.Model.get_absolute_url()`
|
* A model: the model's :meth:`~django.db.models.Model.get_absolute_url()`
|
||||||
function will be called.
|
function will be called.
|
||||||
|
|
||||||
* A view name, possibly with arguments: :func:`urlresolvers.reverse
|
* A view name, possibly with arguments: :func:`~django.urls.reverse` will be
|
||||||
<django.core.urlresolvers.reverse>` will be used to reverse-resolve the
|
used to reverse-resolve the name.
|
||||||
name.
|
|
||||||
|
|
||||||
* An absolute or relative URL, which will be used as-is for the redirect
|
* An absolute or relative URL, which will be used as-is for the redirect
|
||||||
location.
|
location.
|
||||||
|
@ -131,7 +130,7 @@ You can use the :func:`redirect` function in a number of ways.
|
||||||
|
|
||||||
2. By passing the name of a view and optionally some positional or
|
2. By passing the name of a view and optionally some positional or
|
||||||
keyword arguments; the URL will be reverse resolved using the
|
keyword arguments; the URL will be reverse resolved using the
|
||||||
:func:`~django.core.urlresolvers.reverse` method::
|
:func:`~django.urls.reverse` method::
|
||||||
|
|
||||||
def my_view(request):
|
def my_view(request):
|
||||||
...
|
...
|
||||||
|
|
|
@ -533,8 +533,7 @@ layers where URLs are needed:
|
||||||
|
|
||||||
* In templates: Using the :ttag:`url` template tag.
|
* In templates: Using the :ttag:`url` template tag.
|
||||||
|
|
||||||
* In Python code: Using the :func:`django.core.urlresolvers.reverse`
|
* In Python code: Using the :func:`~django.urls.reverse` function.
|
||||||
function.
|
|
||||||
|
|
||||||
* In higher level code related to handling of URLs of Django model instances:
|
* In higher level code related to handling of URLs of Django model instances:
|
||||||
The :meth:`~django.db.models.Model.get_absolute_url` method.
|
The :meth:`~django.db.models.Model.get_absolute_url` method.
|
||||||
|
@ -571,7 +570,7 @@ You can obtain these in template code by using:
|
||||||
|
|
||||||
Or in Python code::
|
Or in Python code::
|
||||||
|
|
||||||
from django.core.urlresolvers import reverse
|
from django.urls import reverse
|
||||||
from django.http import HttpResponseRedirect
|
from django.http import HttpResponseRedirect
|
||||||
|
|
||||||
def redirect_to_year(request):
|
def redirect_to_year(request):
|
||||||
|
@ -671,8 +670,8 @@ the fully qualified name into parts and then tries the following lookup:
|
||||||
|
|
||||||
2. If there is a current application defined, Django finds and returns the URL
|
2. If there is a current application defined, Django finds and returns the URL
|
||||||
resolver for that instance. The current application can be specified with
|
resolver for that instance. The current application can be specified with
|
||||||
the ``current_app`` argument to the
|
the ``current_app`` argument to the :func:`~django.urls.reverse()`
|
||||||
:func:`~django.core.urlresolvers.reverse()` function.
|
function.
|
||||||
|
|
||||||
The :ttag:`url` template tag uses the namespace of the currently resolved
|
The :ttag:`url` template tag uses the namespace of the currently resolved
|
||||||
view as the current application in a
|
view as the current application in a
|
||||||
|
|
|
@ -1360,7 +1360,7 @@ After defining these URL patterns, Django will automatically add the
|
||||||
language prefix to the URL patterns that were added by the ``i18n_patterns``
|
language prefix to the URL patterns that were added by the ``i18n_patterns``
|
||||||
function. Example::
|
function. Example::
|
||||||
|
|
||||||
from django.core.urlresolvers import reverse
|
from django.urls import reverse
|
||||||
from django.utils.translation import activate
|
from django.utils.translation import activate
|
||||||
|
|
||||||
>>> activate('en')
|
>>> activate('en')
|
||||||
|
@ -1414,11 +1414,10 @@ URL patterns can also be marked translatable using the
|
||||||
url(_(r'^news/'), include(news_patterns, namespace='news')),
|
url(_(r'^news/'), include(news_patterns, namespace='news')),
|
||||||
)
|
)
|
||||||
|
|
||||||
After you've created the translations, the
|
After you've created the translations, the :func:`~django.urls.reverse`
|
||||||
:func:`~django.core.urlresolvers.reverse` function will return the URL in the
|
function will return the URL in the active language. Example::
|
||||||
active language. Example::
|
|
||||||
|
|
||||||
from django.core.urlresolvers import reverse
|
from django.urls import reverse
|
||||||
from django.utils.translation import activate
|
from django.utils.translation import activate
|
||||||
|
|
||||||
>>> activate('en')
|
>>> activate('en')
|
||||||
|
|
|
@ -411,7 +411,7 @@ For example, you can create ``myproject/jinja2.py`` with this content::
|
||||||
from __future__ import absolute_import # Python 2 only
|
from __future__ import absolute_import # Python 2 only
|
||||||
|
|
||||||
from django.contrib.staticfiles.storage import staticfiles_storage
|
from django.contrib.staticfiles.storage import staticfiles_storage
|
||||||
from django.core.urlresolvers import reverse
|
from django.urls import reverse
|
||||||
|
|
||||||
from jinja2 import Environment
|
from jinja2 import Environment
|
||||||
|
|
||||||
|
|
|
@ -507,9 +507,8 @@ Specifically, a ``Response`` object has the following attributes:
|
||||||
|
|
||||||
.. attribute:: resolver_match
|
.. attribute:: resolver_match
|
||||||
|
|
||||||
An instance of :class:`~django.core.urlresolvers.ResolverMatch` for the
|
An instance of :class:`~django.urls.ResolverMatch` for the response.
|
||||||
response. You can use the
|
You can use the :attr:`~django.urls.ResolverMatch.func` attribute, for
|
||||||
:attr:`~django.core.urlresolvers.ResolverMatch.func` attribute, for
|
|
||||||
example, to verify the view that served the response::
|
example, to verify the view that served the response::
|
||||||
|
|
||||||
# my_view here is a function based view
|
# my_view here is a function based view
|
||||||
|
@ -520,7 +519,7 @@ Specifically, a ``Response`` object has the following attributes:
|
||||||
self.assertEqual(response.resolver_match.func.__name__, MyView.as_view().__name__)
|
self.assertEqual(response.resolver_match.func.__name__, MyView.as_view().__name__)
|
||||||
|
|
||||||
If the given URL is not found, accessing this attribute will raise a
|
If the given URL is not found, accessing this attribute will raise a
|
||||||
:exc:`~django.core.urlresolvers.Resolver404` exception.
|
:exc:`~django.urls.Resolver404` exception.
|
||||||
|
|
||||||
You can also use dictionary syntax on the response object to query the value
|
You can also use dictionary syntax on the response object to query the value
|
||||||
of any settings in the HTTP headers. For example, you could determine the
|
of any settings in the HTTP headers. For example, you could determine the
|
||||||
|
|
|
@ -10,10 +10,10 @@ from django.contrib.admin.tests import AdminSeleniumWebDriverTestCase
|
||||||
from django.contrib.admin.views.main import ALL_VAR, SEARCH_VAR, ChangeList
|
from django.contrib.admin.views.main import ALL_VAR, SEARCH_VAR, ChangeList
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from django.core.urlresolvers import reverse
|
|
||||||
from django.template import Context, Template
|
from django.template import Context, Template
|
||||||
from django.test import TestCase, ignore_warnings, override_settings
|
from django.test import TestCase, ignore_warnings, override_settings
|
||||||
from django.test.client import RequestFactory
|
from django.test.client import RequestFactory
|
||||||
|
from django.urls import reverse
|
||||||
from django.utils import formats, six
|
from django.utils import formats, six
|
||||||
from django.utils.deprecation import RemovedInDjango20Warning
|
from django.utils.deprecation import RemovedInDjango20Warning
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
from functools import update_wrapper
|
from functools import update_wrapper
|
||||||
|
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from django.core.urlresolvers import reverse
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.http import HttpResponseRedirect
|
from django.http import HttpResponseRedirect
|
||||||
|
from django.urls import reverse
|
||||||
from django.utils.encoding import python_2_unicode_compatible
|
from django.utils.encoding import python_2_unicode_compatible
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -4,9 +4,9 @@ import datetime
|
||||||
|
|
||||||
from django.contrib.admin.utils import quote
|
from django.contrib.admin.utils import quote
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.core.urlresolvers import reverse
|
|
||||||
from django.template.response import TemplateResponse
|
from django.template.response import TemplateResponse
|
||||||
from django.test import TestCase, override_settings
|
from django.test import TestCase, override_settings
|
||||||
|
from django.urls import reverse
|
||||||
|
|
||||||
from .models import Action, Car, Person
|
from .models import Action, Car, Person
|
||||||
|
|
||||||
|
|
|
@ -7,9 +7,9 @@ from django.contrib.admindocs import utils
|
||||||
from django.contrib.admindocs.views import get_return_data_type
|
from django.contrib.admindocs.views import get_return_data_type
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.contrib.sites.models import Site
|
from django.contrib.sites.models import Site
|
||||||
from django.core.urlresolvers import reverse
|
|
||||||
from django.test import TestCase, modify_settings, override_settings
|
from django.test import TestCase, modify_settings, override_settings
|
||||||
from django.test.utils import captured_stderr
|
from django.test.utils import captured_stderr
|
||||||
|
from django.urls import reverse
|
||||||
|
|
||||||
from .models import Company, Person
|
from .models import Company, Person
|
||||||
|
|
||||||
|
|
|
@ -7,8 +7,8 @@ from django.contrib.admin.helpers import InlineAdminForm
|
||||||
from django.contrib.admin.tests import AdminSeleniumWebDriverTestCase
|
from django.contrib.admin.tests import AdminSeleniumWebDriverTestCase
|
||||||
from django.contrib.auth.models import Permission, User
|
from django.contrib.auth.models import Permission, User
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from django.core.urlresolvers import reverse
|
|
||||||
from django.test import RequestFactory, TestCase, override_settings
|
from django.test import RequestFactory, TestCase, override_settings
|
||||||
|
from django.urls import reverse
|
||||||
|
|
||||||
from .admin import InnerInline, site as admin_site
|
from .admin import InnerInline, site as admin_site
|
||||||
from .models import (
|
from .models import (
|
||||||
|
|
|
@ -6,8 +6,8 @@ from django.contrib.admin.models import ADDITION, CHANGE, DELETION, LogEntry
|
||||||
from django.contrib.admin.utils import quote
|
from django.contrib.admin.utils import quote
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from django.core.urlresolvers import reverse
|
|
||||||
from django.test import TestCase, override_settings
|
from django.test import TestCase, override_settings
|
||||||
|
from django.urls import reverse
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
from django.utils.encoding import force_bytes
|
from django.utils.encoding import force_bytes
|
||||||
from django.utils.html import escape
|
from django.utils.html import escape
|
||||||
|
|
|
@ -5,9 +5,9 @@ import datetime
|
||||||
from django.conf.urls import url
|
from django.conf.urls import url
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.core.urlresolvers import reverse
|
|
||||||
from django.test import TestCase, override_settings
|
from django.test import TestCase, override_settings
|
||||||
from django.test.client import RequestFactory
|
from django.test.client import RequestFactory
|
||||||
|
from django.urls import reverse
|
||||||
|
|
||||||
from .models import Article
|
from .models import Article
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,6 @@ from django.contrib.staticfiles.storage import staticfiles_storage
|
||||||
from django.core import mail
|
from django.core import mail
|
||||||
from django.core.checks import Error
|
from django.core.checks import Error
|
||||||
from django.core.files import temp as tempfile
|
from django.core.files import temp as tempfile
|
||||||
from django.core.urlresolvers import NoReverseMatch, resolve, reverse
|
|
||||||
from django.forms.utils import ErrorList
|
from django.forms.utils import ErrorList
|
||||||
from django.template.loader import render_to_string
|
from django.template.loader import render_to_string
|
||||||
from django.template.response import TemplateResponse
|
from django.template.response import TemplateResponse
|
||||||
|
@ -32,6 +31,7 @@ from django.test import (
|
||||||
override_settings, skipUnlessDBFeature,
|
override_settings, skipUnlessDBFeature,
|
||||||
)
|
)
|
||||||
from django.test.utils import override_script_prefix, patch_logger
|
from django.test.utils import override_script_prefix, patch_logger
|
||||||
|
from django.urls import NoReverseMatch, resolve, reverse
|
||||||
from django.utils import formats, six, translation
|
from django.utils import formats, six, translation
|
||||||
from django.utils._os import upath
|
from django.utils._os import upath
|
||||||
from django.utils.cache import get_max_age
|
from django.utils.cache import get_max_age
|
||||||
|
|
|
@ -15,9 +15,9 @@ from django.contrib.admin.tests import AdminSeleniumWebDriverTestCase
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.core.files.storage import default_storage
|
from django.core.files.storage import default_storage
|
||||||
from django.core.files.uploadedfile import SimpleUploadedFile
|
from django.core.files.uploadedfile import SimpleUploadedFile
|
||||||
from django.core.urlresolvers import reverse
|
|
||||||
from django.db.models import CharField, DateField
|
from django.db.models import CharField, DateField
|
||||||
from django.test import SimpleTestCase, TestCase, override_settings
|
from django.test import SimpleTestCase, TestCase, override_settings
|
||||||
|
from django.urls import reverse
|
||||||
from django.utils import six, translation
|
from django.utils import six, translation
|
||||||
|
|
||||||
from . import models
|
from . import models
|
||||||
|
|
|
@ -20,12 +20,12 @@ from django.contrib.auth.views import login as login_view, redirect_to_login
|
||||||
from django.contrib.sessions.middleware import SessionMiddleware
|
from django.contrib.sessions.middleware import SessionMiddleware
|
||||||
from django.contrib.sites.requests import RequestSite
|
from django.contrib.sites.requests import RequestSite
|
||||||
from django.core import mail
|
from django.core import mail
|
||||||
from django.core.urlresolvers import NoReverseMatch, reverse, reverse_lazy
|
|
||||||
from django.db import connection
|
from django.db import connection
|
||||||
from django.http import HttpRequest, QueryDict
|
from django.http import HttpRequest, QueryDict
|
||||||
from django.middleware.csrf import CsrfViewMiddleware, get_token
|
from django.middleware.csrf import CsrfViewMiddleware, get_token
|
||||||
from django.test import TestCase, override_settings
|
from django.test import TestCase, override_settings
|
||||||
from django.test.utils import patch_logger
|
from django.test.utils import patch_logger
|
||||||
|
from django.urls import NoReverseMatch, reverse, reverse_lazy
|
||||||
from django.utils.encoding import force_text
|
from django.utils.encoding import force_text
|
||||||
from django.utils.http import urlquote
|
from django.utils.http import urlquote
|
||||||
from django.utils.six.moves.urllib.parse import ParseResult, urlparse
|
from django.utils.six.moves.urllib.parse import ParseResult, urlparse
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from django.contrib.admin.tests import AdminSeleniumWebDriverTestCase
|
from django.contrib.admin.tests import AdminSeleniumWebDriverTestCase
|
||||||
from django.core.urlresolvers import reverse
|
|
||||||
from django.forms import (
|
from django.forms import (
|
||||||
CheckboxSelectMultiple, ClearableFileInput, RadioSelect, TextInput,
|
CheckboxSelectMultiple, ClearableFileInput, RadioSelect, TextInput,
|
||||||
)
|
)
|
||||||
|
@ -10,6 +9,7 @@ from django.forms.widgets import (
|
||||||
ChoiceFieldRenderer, ChoiceInput, RadioFieldRenderer,
|
ChoiceFieldRenderer, ChoiceInput, RadioFieldRenderer,
|
||||||
)
|
)
|
||||||
from django.test import SimpleTestCase, override_settings
|
from django.test import SimpleTestCase, override_settings
|
||||||
|
from django.urls import reverse
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
from django.utils.encoding import force_text, python_2_unicode_compatible
|
from django.utils.encoding import force_text, python_2_unicode_compatible
|
||||||
from django.utils.safestring import SafeData
|
from django.utils.safestring import SafeData
|
||||||
|
|
|
@ -9,12 +9,12 @@ from django.contrib.auth.models import User
|
||||||
from django.contrib.contenttypes.admin import GenericTabularInline
|
from django.contrib.contenttypes.admin import GenericTabularInline
|
||||||
from django.contrib.contenttypes.forms import generic_inlineformset_factory
|
from django.contrib.contenttypes.forms import generic_inlineformset_factory
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from django.core.urlresolvers import reverse
|
|
||||||
from django.forms.formsets import DEFAULT_MAX_NUM
|
from django.forms.formsets import DEFAULT_MAX_NUM
|
||||||
from django.forms.models import ModelForm
|
from django.forms.models import ModelForm
|
||||||
from django.test import (
|
from django.test import (
|
||||||
RequestFactory, SimpleTestCase, TestCase, override_settings,
|
RequestFactory, SimpleTestCase, TestCase, override_settings,
|
||||||
)
|
)
|
||||||
|
from django.urls import reverse
|
||||||
|
|
||||||
from .admin import MediaInline, MediaPermanentInline, site as admin_site
|
from .admin import MediaInline, MediaPermanentInline, site as admin_site
|
||||||
from .models import Category, Episode, EpisodePermanent, Media, PhoneNumber
|
from .models import Category, Episode, EpisodePermanent, Media, PhoneNumber
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
from django.core.urlresolvers import reverse
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.db.models import QuerySet
|
from django.db.models import QuerySet
|
||||||
from django.db.models.manager import BaseManager
|
from django.db.models.manager import BaseManager
|
||||||
|
from django.urls import reverse
|
||||||
from django.utils.encoding import python_2_unicode_compatible
|
from django.utils.encoding import python_2_unicode_compatible
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -4,10 +4,10 @@ import time
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
from django.core.exceptions import ImproperlyConfigured
|
from django.core.exceptions import ImproperlyConfigured
|
||||||
from django.core.urlresolvers import resolve
|
|
||||||
from django.http import HttpResponse
|
from django.http import HttpResponse
|
||||||
from django.test import RequestFactory, SimpleTestCase, override_settings
|
from django.test import RequestFactory, SimpleTestCase, override_settings
|
||||||
from django.test.utils import require_jinja2
|
from django.test.utils import require_jinja2
|
||||||
|
from django.urls import resolve
|
||||||
from django.views.generic import RedirectView, TemplateView, View
|
from django.views.generic import RedirectView, TemplateView, View
|
||||||
|
|
||||||
from . import views
|
from . import views
|
||||||
|
|
|
@ -2,9 +2,9 @@ from __future__ import unicode_literals
|
||||||
|
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.core.exceptions import ImproperlyConfigured
|
from django.core.exceptions import ImproperlyConfigured
|
||||||
from django.core.urlresolvers import reverse
|
|
||||||
from django.test import SimpleTestCase, TestCase, override_settings
|
from django.test import SimpleTestCase, TestCase, override_settings
|
||||||
from django.test.client import RequestFactory
|
from django.test.client import RequestFactory
|
||||||
|
from django.urls import reverse
|
||||||
from django.views.generic.base import View
|
from django.views.generic.base import View
|
||||||
from django.views.generic.edit import CreateView, FormMixin, ModelFormMixin
|
from django.views.generic.edit import CreateView, FormMixin, ModelFormMixin
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ from __future__ import unicode_literals
|
||||||
|
|
||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.decorators import login_required
|
||||||
from django.core.paginator import Paginator
|
from django.core.paginator import Paginator
|
||||||
from django.core.urlresolvers import reverse, reverse_lazy
|
from django.urls import reverse, reverse_lazy
|
||||||
from django.utils.decorators import method_decorator
|
from django.utils.decorators import method_decorator
|
||||||
from django.views import generic
|
from django.views import generic
|
||||||
|
|
||||||
|
|
|
@ -3,12 +3,12 @@ from __future__ import unicode_literals
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from django.core.exceptions import ImproperlyConfigured
|
from django.core.exceptions import ImproperlyConfigured
|
||||||
from django.core.urlresolvers import clear_url_caches, reverse, translate_url
|
|
||||||
from django.http import HttpResponsePermanentRedirect
|
from django.http import HttpResponsePermanentRedirect
|
||||||
from django.middleware.locale import LocaleMiddleware
|
from django.middleware.locale import LocaleMiddleware
|
||||||
from django.template import Context, Template
|
from django.template import Context, Template
|
||||||
from django.test import SimpleTestCase, override_settings
|
from django.test import SimpleTestCase, override_settings
|
||||||
from django.test.utils import override_script_prefix
|
from django.test.utils import override_script_prefix
|
||||||
|
from django.urls import clear_url_caches, reverse, translate_url
|
||||||
from django.utils import translation
|
from django.utils import translation
|
||||||
from django.utils._os import upath
|
from django.utils._os import upath
|
||||||
|
|
||||||
|
|
|
@ -4,8 +4,8 @@ from django.contrib.messages.api import MessageFailure
|
||||||
from django.contrib.messages.constants import DEFAULT_LEVELS
|
from django.contrib.messages.constants import DEFAULT_LEVELS
|
||||||
from django.contrib.messages.storage import base, default_storage
|
from django.contrib.messages.storage import base, default_storage
|
||||||
from django.contrib.messages.storage.base import Message
|
from django.contrib.messages.storage.base import Message
|
||||||
from django.core.urlresolvers import reverse
|
|
||||||
from django.test import modify_settings, override_settings
|
from django.test import modify_settings, override_settings
|
||||||
|
from django.urls import reverse
|
||||||
from django.utils.translation import ugettext_lazy
|
from django.utils.translation import ugettext_lazy
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
from django.core.urlresolvers import reverse
|
|
||||||
from django.test import SimpleTestCase, override_settings
|
from django.test import SimpleTestCase, override_settings
|
||||||
|
from django.urls import reverse
|
||||||
|
|
||||||
from .urls import ContactFormViewWithMsg
|
from .urls import ContactFormViewWithMsg
|
||||||
|
|
||||||
|
|
|
@ -2,10 +2,10 @@ from django import forms
|
||||||
from django.conf.urls import url
|
from django.conf.urls import url
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.contrib.messages.views import SuccessMessageMixin
|
from django.contrib.messages.views import SuccessMessageMixin
|
||||||
from django.core.urlresolvers import reverse
|
|
||||||
from django.http import HttpResponse, HttpResponseRedirect
|
from django.http import HttpResponse, HttpResponseRedirect
|
||||||
from django.template import engines
|
from django.template import engines
|
||||||
from django.template.response import TemplateResponse
|
from django.template.response import TemplateResponse
|
||||||
|
from django.urls import reverse
|
||||||
from django.views.decorators.cache import never_cache
|
from django.views.decorators.cache import never_cache
|
||||||
from django.views.generic.edit import FormView
|
from django.views.generic.edit import FormView
|
||||||
|
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue