Merge pull request #900 from bmispelon/ticket-20022

Fix #20022: Correctly handle prefixes with url-unsafe characters in reverse()
This commit is contained in:
Jacob Kaplan-Moss 2013-03-13 10:30:48 -07:00 committed by Florian Apolloner
commit 1059da8de6
9 changed files with 438 additions and 428 deletions

View File

@ -388,7 +388,7 @@ class RegexURLResolver(LocaleRegexProvider):
if len(args) != len(params) + len(prefix_args): if len(args) != len(params) + len(prefix_args):
continue continue
unicode_args = [force_text(val) for val in args] unicode_args = [force_text(val) for val in args]
candidate = (prefix_norm + result) % dict(zip(prefix_args + params, unicode_args)) candidate = (prefix_norm.replace('%', '%%') + result) % dict(zip(prefix_args + params, unicode_args))
else: else:
if set(kwargs.keys()) | set(defaults.keys()) != set(params) | set(defaults.keys()) | set(prefix_args): if set(kwargs.keys()) | set(defaults.keys()) != set(params) | set(defaults.keys()) | set(prefix_args):
continue continue

View File

@ -10,29 +10,16 @@ from django.db import models
from django.utils import six from django.utils import six
from django.utils.encoding import python_2_unicode_compatible from django.utils.encoding import python_2_unicode_compatible
from shared_models.models import Author, Book
class Author(models.Model):
name = models.CharField(max_length=100)
class Meta:
ordering = ('name', )
@python_2_unicode_compatible
class Article(models.Model):
headline = models.CharField(max_length=100)
pub_date = models.DateTimeField()
author = models.ForeignKey(Author, blank=True, null=True)
class Meta:
ordering = ('-pub_date', 'headline')
def __str__(self):
return self.headline
class Tag(models.Model): class Tag(models.Model):
articles = models.ManyToManyField(Article) articles = models.ManyToManyField(Book)
name = models.CharField(max_length=100) name = models.CharField(max_length=100)
class Meta: class Meta:
ordering = ('name', ) ordering = ('name', )
@python_2_unicode_compatible @python_2_unicode_compatible
class Season(models.Model): class Season(models.Model):
year = models.PositiveSmallIntegerField() year = models.PositiveSmallIntegerField()
@ -41,6 +28,7 @@ class Season(models.Model):
def __str__(self): def __str__(self):
return six.text_type(self.year) return six.text_type(self.year)
@python_2_unicode_compatible @python_2_unicode_compatible
class Game(models.Model): class Game(models.Model):
season = models.ForeignKey(Season, related_name='games') season = models.ForeignKey(Season, related_name='games')
@ -50,6 +38,7 @@ class Game(models.Model):
def __str__(self): def __str__(self):
return "%s at %s" % (self.away, self.home) return "%s at %s" % (self.away, self.home)
@python_2_unicode_compatible @python_2_unicode_compatible
class Player(models.Model): class Player(models.Model):
name = models.CharField(max_length=100) name = models.CharField(max_length=100)

File diff suppressed because it is too large Load Diff

View File

@ -21,6 +21,7 @@ os.environ['DJANGO_TEST_TEMP_DIR'] = TEMP_DIR
SUBDIRS_TO_SKIP = ['templates'] SUBDIRS_TO_SKIP = ['templates']
ALWAYS_INSTALLED_APPS = [ ALWAYS_INSTALLED_APPS = [
'shared_models',
'django.contrib.contenttypes', 'django.contrib.contenttypes',
'django.contrib.auth', 'django.contrib.auth',
'django.contrib.sites', 'django.contrib.sites',

View File

View File

@ -0,0 +1,30 @@
from django.db import models
from django.utils import timezone
from django.utils.encoding import python_2_unicode_compatible
class Tag(models.Model):
name = models.CharField(max_length=255)
@python_2_unicode_compatible
class Author(models.Model):
name = models.CharField(max_length=100)
def __str__(self):
return self.name
@python_2_unicode_compatible
class Book(models.Model):
name = models.CharField(max_length=200)
pages = models.IntegerField(default=0)
author = models.ForeignKey(Author, null=True)
pubdate = models.DateTimeField()
tags = models.ManyToManyField(Tag)
class Meta:
ordering = ['-pubdate', 'name']
def __str__(self):
return self.name

View File

@ -1,18 +0,0 @@
from django.db import models
from django.utils.encoding import python_2_unicode_compatible
@python_2_unicode_compatible
class Author(models.Model):
name = models.CharField(max_length=20)
def __str__(self):
return self.name
@python_2_unicode_compatible
class Book(models.Model):
name = models.CharField(max_length=20)
authors = models.ManyToManyField(Author)
def __str__(self):
return self.name

View File

@ -3,7 +3,7 @@ from __future__ import absolute_import
from django.db import models from django.db import models
from django.test import TestCase from django.test import TestCase
from .models import Author, Book from shared_models.models import Author, Book
class SignalsRegressTests(TestCase): class SignalsRegressTests(TestCase):
@ -77,7 +77,7 @@ class SignalsRegressTests(TestCase):
"Is created" "Is created"
]) ])
b1 = Book(name='Snow Crash') b1 = Book(name='Snow Crash', pubdate='2012-02-02 12:00')
self.assertEqual(self.get_signal_output(b1.save), [ self.assertEqual(self.get_signal_output(b1.save), [
"pre_save signal, Snow Crash", "pre_save signal, Snow Crash",
"post_save signal, Snow Crash", "post_save signal, Snow Crash",
@ -87,7 +87,7 @@ class SignalsRegressTests(TestCase):
def test_m2m_signals(self): def test_m2m_signals(self):
""" Assigning and removing to/from m2m shouldn't generate an m2m signal """ """ Assigning and removing to/from m2m shouldn't generate an m2m signal """
b1 = Book(name='Snow Crash') b1 = Book(name='Snow Crash', pubdate='2012-02-02 12:00')
self.get_signal_output(b1.save) self.get_signal_output(b1.save)
a1 = Author(name='Neal Stephenson') a1 = Author(name='Neal Stephenson')
self.get_signal_output(a1.save) self.get_signal_output(a1.save)

View File

@ -183,6 +183,11 @@ class URLPatternReverse(TestCase):
self.assertEqual('/bump%2520map/includes/non_path_include/', self.assertEqual('/bump%2520map/includes/non_path_include/',
reverse('non_path_include', prefix='/bump%20map/')) reverse('non_path_include', prefix='/bump%20map/'))
def test_non_urlsafe_prefix_with_args(self):
# Regression for #20022
self.assertEqual('/%7Eme/places/1/',
reverse('places', args=[1], prefix='/~me/'))
class ResolverTests(unittest.TestCase): class ResolverTests(unittest.TestCase):
def test_resolver_repr(self): def test_resolver_repr(self):
""" """