Ticket #8648: 8648.3.diff
File 8648.3.diff, 10.2 KB (added by , 16 years ago) |
---|
-
django/db/models/fields/related.py
686 686 setattr(cls, related.get_accessor_name(), ForeignRelatedObjectsDescriptor(related)) 687 687 688 688 def formfield(self, **kwargs): 689 defaults = {'form_class': forms.ModelChoiceField, 'queryset': self.rel.to._default_manager.complex_filter(self.rel.limit_choices_to)} 689 defaults = { 690 'form_class': forms.ModelChoiceField, 691 'queryset': self.rel.to._default_manager.complex_filter( 692 self.rel.limit_choices_to), 693 'to_field_name': self.rel.field_name, 694 } 690 695 defaults.update(kwargs) 691 696 return super(ForeignKey, self).formfield(**defaults) 692 697 -
django/forms/models.py
460 460 if self.field.cache_choices: 461 461 if self.field.choice_cache is None: 462 462 self.field.choice_cache = [ 463 (obj.pk, self.field.label_from_instance(obj)) 464 for obj in self.queryset.all() 463 self.choice(obj) for obj in self.queryset.all() 465 464 ] 466 465 for choice in self.field.choice_cache: 467 466 yield choice 468 467 else: 469 468 for obj in self.queryset.all(): 470 yield (obj.pk, self.field.label_from_instance(obj))469 yield self.choice(obj) 471 470 471 def choice(self, obj): 472 if self.field.to_field_name: 473 key = getattr(obj, self.field.to_field_name) 474 else: 475 key = obj.pk 476 return (key, self.field.label_from_instance(obj)) 477 478 472 479 class ModelChoiceField(ChoiceField): 473 480 """A ChoiceField whose choices are a model QuerySet.""" 474 481 # This class is a subclass of ChoiceField for purity, but it doesn't … … 480 487 481 488 def __init__(self, queryset, empty_label=u"---------", cache_choices=False, 482 489 required=True, widget=None, label=None, initial=None, 483 help_text=None, *args, **kwargs):490 help_text=None, to_field_name=None, *args, **kwargs): 484 491 self.empty_label = empty_label 485 492 self.cache_choices = cache_choices 486 493 … … 490 497 *args, **kwargs) 491 498 self.queryset = queryset 492 499 self.choice_cache = None 500 self.to_field_name = to_field_name 493 501 494 502 def _get_queryset(self): 495 503 return self._queryset … … 532 540 if value in EMPTY_VALUES: 533 541 return None 534 542 try: 535 value = self.queryset.get(pk=value) 543 key = self.to_field_name or 'pk' 544 value = self.queryset.get(**{key: value}) 536 545 except self.queryset.model.DoesNotExist: 537 546 raise ValidationError(self.error_messages['invalid_choice']) 538 547 return value -
tests/modeltests/model_forms/models.py
78 78 class WriterProfile(models.Model): 79 79 writer = models.OneToOneField(Writer, primary_key=True) 80 80 age = models.PositiveIntegerField() 81 81 82 82 def __unicode__(self): 83 83 return "%s is %s" % (self.writer, self.age) 84 84 … … 120 120 class ArticleStatus(models.Model): 121 121 status = models.CharField(max_length=2, choices=ARTICLE_STATUS_CHAR, blank=True, null=True) 122 122 123 class Inventory(models.Model): 124 barcode = models.PositiveIntegerField(unique=True) 125 parent = models.ForeignKey('self', to_field='barcode', blank=True, null=True) 126 name = models.CharField(blank=False, max_length=20) 127 128 def __unicode__(self): 129 return self.name 130 123 131 __test__ = {'API_TESTS': """ 124 132 >>> from django import forms 125 133 >>> from django.forms.models import ModelForm, model_to_dict … … 1117 1125 Traceback (most recent call last): 1118 1126 ... 1119 1127 ValidationError: [u'Enter only digits separated by commas.'] 1120 >>> f.clean(',,,,') 1128 >>> f.clean(',,,,') 1121 1129 u',,,,' 1122 1130 >>> f.clean('1.2') 1123 1131 Traceback (most recent call last): … … 1152 1160 ... 1153 1161 ValidationError: [u'Select a valid choice. z is not one of the available choices.'] 1154 1162 1163 # Foreign keys which use to_field ############################################# 1164 1165 >>> apple = Inventory.objects.create(barcode=86, name='Apple') 1166 >>> pear = Inventory.objects.create(barcode=22, name='Pear') 1167 >>> core = Inventory.objects.create(barcode=87, name='Core', parent=apple) 1168 1169 >>> field = ModelChoiceField(Inventory.objects.all(), to_field_name='barcode') 1170 >>> for choice in field.choices: 1171 ... print choice 1172 (u'', u'---------') 1173 (86, u'Apple') 1174 (22, u'Pear') 1175 (87, u'Core') 1176 1177 >>> class InventoryForm(ModelForm): 1178 ... class Meta: 1179 ... model = Inventory 1180 >>> form = InventoryForm(instance=core) 1181 >>> print form['parent'] 1182 <select name="parent" id="id_parent"> 1183 <option value="">---------</option> 1184 <option value="86" selected="selected">Apple</option> 1185 <option value="22">Pear</option> 1186 <option value="87">Core</option> 1187 </select> 1188 1189 >>> data = model_to_dict(core) 1190 >>> data['parent'] = '22' 1191 >>> form = InventoryForm(data=data, instance=core) 1192 >>> core = form.save() 1193 >>> core.parent 1194 <Inventory: Pear> 1155 1195 """} -
tests/regressiontests/admin_widgets/models.py
5 5 6 6 class Member(models.Model): 7 7 name = models.CharField(max_length=100) 8 8 9 9 def __unicode__(self): 10 10 return self.name 11 11 12 12 class Band(models.Model): 13 13 name = models.CharField(max_length=100) 14 14 members = models.ManyToManyField(Member) 15 15 16 16 def __unicode__(self): 17 17 return self.name 18 18 … … 20 20 band = models.ForeignKey(Band) 21 21 name = models.CharField(max_length=100) 22 22 cover_art = models.FileField(upload_to='albums') 23 23 24 24 def __unicode__(self): 25 25 return self.name 26 26 27 class Inventory(models.Model): 28 barcode = models.PositiveIntegerField(unique=True) 29 parent = models.ForeignKey('self', to_field='barcode', blank=True, null=True) 30 name = models.CharField(blank=False, max_length=20) 31 32 def __unicode__(self): 33 return self.name 34 27 35 __test__ = {'WIDGETS_TESTS': """ 28 36 >>> from datetime import datetime 29 37 >>> from django.utils.html import escape, conditional_escape … … 84 92 >>> w._has_changed([1, 2], [u'1', u'3']) 85 93 True 86 94 95 # Check that ForeignKeyRawIdWidget works with fields which aren't related to 96 # the model's primary key. 97 >>> apple = Inventory.objects.create(barcode=86, name='Apple') 98 >>> pear = Inventory.objects.create(barcode=22, name='Pear') 99 >>> core = Inventory.objects.create(barcode=87, name='Core', parent=apple) 100 >>> rel = Inventory._meta.get_field('parent').rel 101 >>> w = ForeignKeyRawIdWidget(rel) 102 >>> print w.render('test', core.parent_id, attrs={}) 103 <input type="text" name="test" value="86" class="vForeignKeyRawIdAdminField" /><a href="../../../admin_widgets/inventory/" class="related-lookup" id="lookup_id_test" onclick="return showRelatedObjectLookupPopup(this);"> <img src="/admin_media/img/admin/selector-search.gif" width="16" height="16" alt="Lookup" /></a> <strong>Apple</strong> 87 104 """ % { 88 105 'ADMIN_MEDIA_PREFIX': settings.ADMIN_MEDIA_PREFIX, 89 106 'STORAGE_URL': default_storage.url(''), -
django/contrib/admin/widgets.py
41 41 42 42 class AdminDateWidget(forms.TextInput): 43 43 class Media: 44 js = (settings.ADMIN_MEDIA_PREFIX + "js/calendar.js", 44 js = (settings.ADMIN_MEDIA_PREFIX + "js/calendar.js", 45 45 settings.ADMIN_MEDIA_PREFIX + "js/admin/DateTimeShortcuts.js") 46 46 47 47 def __init__(self, attrs={}): 48 48 super(AdminDateWidget, self).__init__(attrs={'class': 'vDateField', 'size': '10'}) 49 49 50 50 class AdminTimeWidget(forms.TextInput): 51 51 class Media: 52 js = (settings.ADMIN_MEDIA_PREFIX + "js/calendar.js", 52 js = (settings.ADMIN_MEDIA_PREFIX + "js/calendar.js", 53 53 settings.ADMIN_MEDIA_PREFIX + "js/admin/DateTimeShortcuts.js") 54 54 55 55 def __init__(self, attrs={}): 56 56 super(AdminTimeWidget, self).__init__(attrs={'class': 'vTimeField', 'size': '8'}) 57 57 58 58 class AdminSplitDateTime(forms.SplitDateTimeWidget): 59 59 """ 60 60 A SplitDateTime Widget that has some admin-specific styling. … … 86 86 """ 87 87 def __init__(self, attrs={}): 88 88 super(AdminFileWidget, self).__init__(attrs) 89 89 90 90 def render(self, name, value, attrs=None): 91 91 output = [] 92 92 if value and hasattr(value, "url"): … … 121 121 if value: 122 122 output.append(self.label_for_value(value)) 123 123 return mark_safe(u''.join(output)) 124 124 125 125 def label_for_value(self, value): 126 return ' <strong>%s</strong>' % \ 127 truncate_words(self.rel.to.objects.get(pk=value), 14) 128 126 key = self.rel.get_related_field().name 127 obj = self.rel.to.objects.get(**{key: value}) 128 return ' <strong>%s</strong>' % truncate_words(obj, 14) 129 129 130 class ManyToManyRawIdWidget(ForeignKeyRawIdWidget): 130 131 """ 131 132 A Widget for displaying ManyToMany ids in the "raw_id" interface rather than … … 133 134 """ 134 135 def __init__(self, rel, attrs=None): 135 136 super(ManyToManyRawIdWidget, self).__init__(rel, attrs) 136 137 137 138 def render(self, name, value, attrs=None): 138 139 attrs['class'] = 'vManyToManyRawIdAdminField' 139 140 if value: … … 141 142 else: 142 143 value = '' 143 144 return super(ManyToManyRawIdWidget, self).render(name, value, attrs) 144 145 145 146 def label_for_value(self, value): 146 147 return '' 147 148 … … 152 153 if value: 153 154 return [value] 154 155 return None 155 156 156 157 def _has_changed(self, initial, data): 157 158 if initial is None: 158 159 initial = []