Commit bc7923be authored by Marten Kenbeek's avatar Marten Kenbeek Committed by Tim Graham
Browse files

Fixed #24127 -- Changed the default current_app to the current namespace.

Changed the url template tag to use request.resolver_match.namespace as a
default for the current_app argument if request.current_app is not set.
parent 6024fd5d
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -152,6 +152,10 @@ class Context(BaseContext):
    def current_app(self):
        return None if self._current_app is _current_app_undefined else self._current_app

    @property
    def is_current_app_set(self):
        return self._current_app is not _current_app_undefined

    @contextmanager
    def bind_template(self, template):
        if self.template is not None:
+9 −2
Original line number Diff line number Diff line
@@ -479,9 +479,16 @@ class URLNode(Node):
        try:
            current_app = context.request.current_app
        except AttributeError:
            # Change the fallback value to None when the deprecation path for
            # Leave only the else block when the deprecation path for
            # Context.current_app completes in Django 1.10.
            # Can also remove the Context.is_current_app_set property.
            if context.is_current_app_set:
                current_app = context.current_app
            else:
                try:
                    current_app = context.request.resolver_match.namespace
                except AttributeError:
                    current_app = None

        # Try to look up the URL twice: once given the view name, and again
        # relative to what we guess is the "main" app. If they both fail,
+6 −0
Original line number Diff line number Diff line
@@ -895,6 +895,12 @@ Miscellaneous
  whitespace by default. This can be disabled by setting the new
  :attr:`~django.forms.CharField.strip` argument to ``False``.

* If neither :attr:`request.current_app <django.http.HttpRequest.current_app>`
  nor :class:`Context.current_app <django.template.Context>` are set, the
  :ttag:`url` template tag will now use the namespace of the current request.
  Set ``request.current_app`` to ``None`` if you don't want to use a namespace
  hint.

.. _deprecated-features-1.9:

Features deprecated in 1.9
+15 −14
Original line number Diff line number Diff line
@@ -669,11 +669,16 @@ the fully qualified name into parts and then tries the following lookup:
   example, ``'polls'``). This will yield a list of instances of that
   application.

2. If there is a *current* application defined, Django finds and returns
   the URL resolver for that instance. The *current* application can be
   specified as an attribute on the request. Applications that expect to
   have multiple deployments should set the ``current_app`` attribute on
   the ``request`` being processed.
2. If there is a current application defined, Django finds and returns the URL
   resolver for that instance. The current application can be specified with
   the ``current_app`` argument to the
   :func:`~django.core.urlresolvers.reverse()` function.

   The :ttag:`url` template tag uses the namespace of the currently resolved
   view as the current application in a
   :class:`~django.template.RequestContext`. You can override this default by
   setting the current application on the :attr:`request.current_app
   <django.http.HttpRequest.current_app>` attribute.

   .. versionchanged:: 1.8

@@ -682,8 +687,11 @@ the fully qualified name into parts and then tries the following lookup:
      :class:`~django.template.RequestContext` that is used to render a
      template.

   The current application can also be specified manually as an argument
   to the :func:`~django.core.urlresolvers.reverse` function.
   .. versionchanged:: 1.9

      Previously, the :ttag:`url` template tag did not use the namespace of the
      currently resolved view and you had to set the ``current_app`` attribute
      on the request.

3. If there is no current application. Django looks for a default
   application instance. The default application instance is the instance
@@ -751,13 +759,6 @@ Using this setup, the following lookups are possible:

    {% url 'polls:index' %}

  Note that reversing in the template requires the ``current_app`` be added as
  an attribute to the ``request`` like this::

    def render_to_response(self, context, **response_kwargs):
        self.request.current_app = self.request.resolver_match.namespace
        return super(DetailView, self).render_to_response(context, **response_kwargs)

* If there is no current instance - say, if we were rendering a page
  somewhere else on the site - ``'polls:index'`` will resolve to the last
  registered instance of ``polls``. Since there is no default instance
+31 −3
Original line number Diff line number Diff line
# coding: utf-8
from django.core.urlresolvers import NoReverseMatch
from django.template import TemplateSyntaxError
from django.test import SimpleTestCase, ignore_warnings, override_settings
from django.core.urlresolvers import NoReverseMatch, resolve
from django.template import RequestContext, TemplateSyntaxError
from django.test import (
    RequestFactory, SimpleTestCase, ignore_warnings, override_settings,
)
from django.utils.deprecation import RemovedInDjango110Warning

from ..utils import setup
@@ -252,3 +254,29 @@ class UrlTagTests(SimpleTestCase):
    def test_url_asvar03(self):
        output = self.engine.render_to_string('url-asvar03')
        self.assertEqual(output, '')

    @setup({'url-namespace01': '{% url "app:named.client" 42 %}'})
    def test_url_namespace01(self):
        request = RequestFactory().get('/')
        request.resolver_match = resolve('/ns1/')
        template = self.engine.get_template('url-namespace01')
        context = RequestContext(request)
        output = template.render(context)
        self.assertEqual(output, '/ns1/named-client/42/')

    @setup({'url-namespace02': '{% url "app:named.client" 42 %}'})
    def test_url_namespace02(self):
        request = RequestFactory().get('/')
        request.resolver_match = resolve('/ns2/')
        template = self.engine.get_template('url-namespace02')
        context = RequestContext(request)
        output = template.render(context)
        self.assertEqual(output, '/ns2/named-client/42/')

    @setup({'url-namespace03': '{% url "app:named.client" 42 %}'})
    def test_url_namespace03(self):
        request = RequestFactory().get('/')
        template = self.engine.get_template('url-namespace03')
        context = RequestContext(request)
        output = template.render(context)
        self.assertEqual(output, '/ns2/named-client/42/')
Loading