diff --git a/django/contrib/auth/views.py b/django/contrib/auth/views.py
index 42ad68d..0325643 100644
a
|
b
|
def redirect_to_login(next, login_url=None,
|
99 | 99 | if redirect_field_name: |
100 | 100 | querystring = QueryDict(login_url_parts[4], mutable=True) |
101 | 101 | querystring[redirect_field_name] = next |
102 | | login_url_parts[4] = querystring.urlencode() |
| 102 | login_url_parts[4] = querystring.urlencode(safe='/') |
103 | 103 | |
104 | 104 | return HttpResponseRedirect(urlparse.urlunparse(login_url_parts)) |
105 | 105 | |
diff --git a/django/http/__init__.py b/django/http/__init__.py
index 42027f0..0068519 100644
a
|
b
|
import os
|
3 | 3 | import re |
4 | 4 | import time |
5 | 5 | from pprint import pformat |
6 | | from urllib import urlencode |
| 6 | from urllib import urlencode, quote |
7 | 7 | from urlparse import urljoin |
8 | 8 | try: |
9 | 9 | from cStringIO import StringIO |
… |
… |
class QueryDict(MultiValueDict):
|
363 | 363 | """Returns a mutable copy of this object.""" |
364 | 364 | return self.__deepcopy__({}) |
365 | 365 | |
366 | | def urlencode(self): |
| 366 | def urlencode(self, safe=None): |
| 367 | """ |
| 368 | Returns an encoded string of all query string arguments. |
| 369 | |
| 370 | :arg safe: Used to specify characters which do not require quoting, for |
| 371 | example:: |
| 372 | |
| 373 | >>> q = QueryDict('', mutable=True) |
| 374 | >>> q['next'] = '/a&b/' |
| 375 | >>> q.urlencode() |
| 376 | 'next=%2Fa%26b%2F' |
| 377 | >>> q.urlencode(safe='/') |
| 378 | 'next=/a%26b/' |
| 379 | """ |
367 | 380 | output = [] |
| 381 | if safe: |
| 382 | encode = lambda k, v: '%s=%s' % ((quote(k, safe), quote(v, safe))) |
| 383 | else: |
| 384 | encode = lambda k, v: urlencode({k: v}) |
368 | 385 | for k, list_ in self.lists(): |
369 | 386 | k = smart_str(k, self.encoding) |
370 | | output.extend([urlencode({k: smart_str(v, self.encoding)}) for v in list_]) |
| 387 | for value in list_: |
| 388 | output.append(encode(k, smart_str(value, self.encoding))) |
371 | 389 | return '&'.join(output) |
372 | 390 | |
373 | 391 | class CompatCookie(SimpleCookie): |
diff --git a/tests/regressiontests/httpwrappers/tests.py b/tests/regressiontests/httpwrappers/tests.py
index 6d45252..a744e6a 100644
a
|
b
|
class QueryDictTests(unittest.TestCase):
|
71 | 71 | |
72 | 72 | self.assertEqual(q.urlencode(), 'foo=bar') |
73 | 73 | |
| 74 | def test_urlencode(self): |
| 75 | q = QueryDict('', mutable=True) |
| 76 | q['next'] = '/a&b/' |
| 77 | self.assertEqual(q.urlencode(), 'next=%2Fa%26b%2F') |
| 78 | self.assertEqual(q.urlencode(safe='/'), 'next=/a%26b/') |
| 79 | |
74 | 80 | def test_mutable_copy(self): |
75 | 81 | """A copy of a QueryDict is mutable.""" |
76 | 82 | q = QueryDict('').copy() |