mirror of
				https://github.com/django/django.git
				synced 2025-10-31 09:41:08 +00:00 
			
		
		
		
	[1.7.x] Fixed #23112 -- Field.get_choices tries to index an iterable
Backport of 97a38de230 from master.
			
			
This commit is contained in:
		
				
					committed by
					
						 Florian Apolloner
						Florian Apolloner
					
				
			
			
				
	
			
			
			
						parent
						
							5736631233
						
					
				
				
					commit
					e22ad1c325
				
			| @@ -730,9 +730,10 @@ class Field(RegisterLookupMixin): | ||||
|         """Returns choices with a default blank choices included, for use | ||||
|         as SelectField choices for this field.""" | ||||
|         blank_defined = False | ||||
|         named_groups = self.choices and isinstance(self.choices[0][1], (list, tuple)) | ||||
|         choices = list(self.choices) if self.choices else [] | ||||
|         named_groups = choices and isinstance(choices[0][1], (list, tuple)) | ||||
|         if not named_groups: | ||||
|             for choice, __ in self.choices: | ||||
|             for choice, __ in choices: | ||||
|                 if choice in ('', None): | ||||
|                     blank_defined = True | ||||
|                     break | ||||
| @@ -740,7 +741,7 @@ class Field(RegisterLookupMixin): | ||||
|         first_choice = (blank_choice if include_blank and | ||||
|                         not blank_defined else []) | ||||
|         if self.choices: | ||||
|             return first_choice + list(self.choices) | ||||
|             return first_choice + choices | ||||
|         rel_model = self.rel.to | ||||
|         if hasattr(self.rel, 'get_related_field'): | ||||
|             lst = [(getattr(x, self.rel.get_related_field().attname), | ||||
|   | ||||
| @@ -45,6 +45,29 @@ class Whiz(models.Model): | ||||
|     c = models.IntegerField(choices=CHOICES, null=True) | ||||
|  | ||||
|  | ||||
| class Counter: | ||||
|     def __init__(self): | ||||
|         self.n = 1 | ||||
|  | ||||
|     def __iter__(self): | ||||
|         return self | ||||
|  | ||||
|     def next(self):  # Python 3: def __next__(self) | ||||
|         if self.n > 5: | ||||
|             raise StopIteration | ||||
|         else: | ||||
|             self.n += 1 | ||||
|             return (self.n, 'val-'+str(self.n)) | ||||
|  | ||||
|  | ||||
| class WhizIter(models.Model): | ||||
|     c = models.IntegerField(choices=Counter(), null=True) | ||||
|  | ||||
|  | ||||
| class WhizIterEmpty(models.Model): | ||||
|     c = models.CharField(choices=(x for x in []), blank=True, max_length=1) | ||||
|  | ||||
|  | ||||
| class BigD(models.Model): | ||||
|     d = models.DecimalField(max_digits=38, decimal_places=30) | ||||
|  | ||||
|   | ||||
| @@ -25,7 +25,8 @@ from .models import ( | ||||
|     Foo, Bar, Whiz, BigD, BigS, BigIntegerModel, Post, NullBooleanModel, | ||||
|     BooleanModel, PrimaryKeyCharModel, DataModel, Document, RenamedField, | ||||
|     DateTimeModel, VerboseNameField, FksToBooleans, FkToChar, FloatModel, | ||||
|     SmallIntegerModel, IntegerModel, PositiveSmallIntegerModel, PositiveIntegerModel) | ||||
|     SmallIntegerModel, IntegerModel, PositiveSmallIntegerModel, PositiveIntegerModel, | ||||
|     WhizIter, WhizIterEmpty) | ||||
|  | ||||
|  | ||||
| class BasicFieldTests(test.TestCase): | ||||
| @@ -375,6 +376,31 @@ class ChoicesTests(test.TestCase): | ||||
|         self.assertEqual(Whiz(c=None).get_c_display(), None)    # Blank value | ||||
|         self.assertEqual(Whiz(c='').get_c_display(), '')        # Empty value | ||||
|  | ||||
|     def test_iterator_choices(self): | ||||
|         """ | ||||
|         Check that get_choices works with Iterators (#23112). | ||||
|         """ | ||||
|         self.assertEqual(WhizIter(c=1).c, 1)          # A nested value | ||||
|         self.assertEqual(WhizIter(c=9).c, 9)          # Invalid value | ||||
|         self.assertEqual(WhizIter(c=None).c, None)    # Blank value | ||||
|         self.assertEqual(WhizIter(c='').c, '')        # Empty value | ||||
|  | ||||
|     def test_empty_iterator_choices(self): | ||||
|         """ | ||||
|         Check that get_choices works with empty iterators (#23112). | ||||
|         """ | ||||
|         self.assertEqual(WhizIterEmpty(c="a").c, "a")      # A nested value | ||||
|         self.assertEqual(WhizIterEmpty(c="b").c, "b")      # Invalid value | ||||
|         self.assertEqual(WhizIterEmpty(c=None).c, None)    # Blank value | ||||
|         self.assertEqual(WhizIterEmpty(c='').c, '')        # Empty value | ||||
|  | ||||
|     def test_charfield_get_choices_with_blank_iterator(self): | ||||
|         """ | ||||
|         Check that get_choices works with an empty Iterator | ||||
|         """ | ||||
|         f = models.CharField(choices=(x for x in [])) | ||||
|         self.assertEqual(f.get_choices(include_blank=True), [('', '---------')]) | ||||
|  | ||||
|  | ||||
| class SlugFieldTests(test.TestCase): | ||||
|     def test_slugfield_max_length(self): | ||||
|   | ||||
		Reference in New Issue
	
	Block a user