mirror of https://github.com/django/django.git
Merge pull request #900 from bmispelon/ticket-20022
Fix #20022: Correctly handle prefixes with url-unsafe characters in reverse()
This commit is contained in:
commit
1059da8de6
|
@ -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
|
||||||
|
|
|
@ -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
|
@ -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',
|
||||||
|
|
|
@ -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
|
|
@ -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
|
|
|
@ -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)
|
||||||
|
|
|
@ -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):
|
||||||
"""
|
"""
|
||||||
|
|
Loading…
Reference in New Issue