diff --git a/django/contrib/auth/tests/test_views.py b/django/contrib/auth/tests/test_views.py
index d406b43..7259eda 100644
a
|
b
|
|
| 1 | # -*- coding: utf-8 -*- |
1 | 2 | from importlib import import_module |
2 | 3 | import itertools |
3 | 4 | import re |
… |
… |
from django.contrib.auth import SESSION_KEY, REDIRECT_FIELD_NAME
|
10 | 11 | from django.contrib.auth.forms import (AuthenticationForm, PasswordChangeForm, |
11 | 12 | SetPasswordForm) |
12 | 13 | from django.contrib.auth.models import User |
13 | | from django.contrib.auth.views import login as login_view |
| 14 | from django.contrib.auth.views import login as login_view, redirect_to_login |
14 | 15 | from django.core import mail |
15 | | from django.core.urlresolvers import reverse, NoReverseMatch |
| 16 | from django.core.urlresolvers import NoReverseMatch, reverse, reverse_lazy |
16 | 17 | from django.http import QueryDict, HttpRequest |
17 | 18 | from django.utils.deprecation import RemovedInDjango20Warning |
18 | 19 | from django.utils.encoding import force_text |
… |
… |
class LoginRedirectUrlTest(AuthViewsTestCase):
|
673 | 674 | self.assertLoginRedirectURLEqual('http://remote.example.com/welcome/') |
674 | 675 | |
675 | 676 | |
| 677 | class LazyLoginURLTest(AuthViewsTestCase): |
| 678 | def test_redirect_to_login(self): |
| 679 | with self.settings(LOGIN_URL=reverse_lazy('login')): |
| 680 | login_redirect_response = redirect_to_login(next='/else/where/') |
| 681 | expected = '/login/?next=/else/where/' |
| 682 | self.assertEquals(expected, login_redirect_response.url) |
| 683 | |
| 684 | def test_redirect_to_login_with_unicode(self): |
| 685 | with self.settings(LOGIN_URL=reverse_lazy('login')): |
| 686 | login_redirect_response = redirect_to_login(next='/else/where/เค/') |
| 687 | expected = '/login/?next=/else/where/%E0%A4%9D/' |
| 688 | self.assertEquals(expected, login_redirect_response.url) |
| 689 | |
| 690 | |
676 | 691 | @skipIfCustomUser |
677 | 692 | class LogoutTest(AuthViewsTestCase): |
678 | 693 | |
diff --git a/django/contrib/auth/views.py b/django/contrib/auth/views.py
index 348fca8..0031785 100644
a
|
b
|
def redirect_to_login(next, login_url=None,
|
125 | 125 | |
126 | 126 | login_url_parts = list(urlparse(resolved_url)) |
127 | 127 | if redirect_field_name: |
128 | | querystring = QueryDict(login_url_parts[4], mutable=True) |
| 128 | old_querystring = login_url_parts[4] |
| 129 | querystring = QueryDict(old_querystring, mutable=True) |
129 | 130 | querystring[redirect_field_name] = next |
130 | | login_url_parts[4] = querystring.urlencode(safe='/') |
| 131 | new_querystring = querystring.urlencode(safe='/') |
| 132 | if isinstance(old_querystring, bytes): |
| 133 | # login_url_parts must be all str / all bytes, not a mix in Python3 |
| 134 | new_querystring = new_querystring.encode('utf-8') |
| 135 | login_url_parts[4] = new_querystring |
131 | 136 | |
132 | 137 | return HttpResponseRedirect(urlunparse(login_url_parts)) |
133 | 138 | |
diff --git a/django/utils/functional.py b/django/utils/functional.py
index aa0d6f8..634d06e 100644
a
|
b
|
def lazy(func, *resultclasses):
|
182 | 182 | memo[id(self)] = self |
183 | 183 | return self |
184 | 184 | |
| 185 | def decode(self, encoding='ascii', errors='strict'): |
| 186 | """ |
| 187 | Turn into a string as that's what Python 3 code usually wants, |
| 188 | e.g. to pass the _coerce_args function in urlparse. |
| 189 | |
| 190 | :param encoding: So urllib.parse._decode_args works with this. |
| 191 | :param errors: So urllib.parse._decode_args works with this. |
| 192 | """ |
| 193 | return str(self) |
| 194 | |
185 | 195 | @wraps(func) |
186 | 196 | def __wrapper__(*args, **kw): |
187 | 197 | # Creates the proxy object, instead of the actual value. |