Opened 18 years ago
Closed 17 years ago
#2470 closed defect (duplicate)
unique_together and edit_inline causes error in admin, depending on uniqueness order
Reported by: | Owned by: | Adrian Holovaty | |
---|---|---|---|
Component: | contrib.admin | Version: | dev |
Severity: | normal | Keywords: | |
Cc: | Triage Stage: | Unreviewed | |
Has patch: | no | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
Given this model snippet, I get an error displaying Country objects in the admin.
The error message is: 'ChangeManipulator' object has no attribute 'isUniquecountry_price'
class Amount( models.Model): amount = models.FloatField( _("Amount"), decimal_places=2, max_digits=5, core=True) country = models.ForeignKey( Country) price = models.ForeignKey( Price, edit_inline=models.TABULAR) class Meta: verbose_name = _('Amount') verbose_name_plural = _('Amounts') unique_together = (('country', 'price'),)
However, the error does not occur if the uniqueness constraint is changed to read:
unique_together = (('price', 'country'),)
(Postgres, 0.95 rev 3512)
Change History (5)
comment:1 by , 18 years ago
comment:2 by , 18 years ago
The traceback with some more info in it, if it can help:
# /usr/local/lib/python2.4/site-packages/django/contrib/admin/views/main.py in change_stage 306. if not request.user.has_perm(app_label + '.' + opts.get_change_permission()): 307. raise PermissionDenied 308. 309. if request.POST and request.POST.has_key("_saveasnew"): 310. return add_stage(request, app_label, model_name, form_url='../../add/') 311. 312. try: 313. manipulator = model.ChangeManipulator(object_id) ... 314. except ObjectDoesNotExist: 315. raise Http404 316. 317. if request.POST: 318. new_data = request.POST.copy() 319. ▼ Local vars Variable Value app_label 'poll' model <class 'devel.poll.models.Poll'> model_name 'poll' object_id '1' opts <Options for Poll> request <WSGIRequest GET:<MultiValueDict: {}>, [...] # /usr/local/lib/python2.4/site-packages/django/db/models/manipulators.py in __init__ 265. lookup_kwargs = {'%s__exact' % self.opts.one_to_one_field.rel.field_name: obj_key} 266. self.opts.one_to_one_field.rel.to.get_model_module().complex_filter(limit_choices_to).get(**lookup_kwargs) 267. params = dict([(f.attname, f.get_default()) for f in self.opts.fields]) 268. params[self.opts.pk.attname] = obj_key 269. self.original_object = self.opts.get_model_module().Klass(**params) 270. else: 271. raise 272. super(AutomaticChangeManipulator, self).__init__(follow=follow) ... 273. 274. def manipulator_validator_unique_together(field_name_list, opts, self, field_data, all_data): 275. from django.db.models.fields.related import ManyToOneRel 276. from django.utils.text import get_text_list 277. field_list = [opts.get_field(field_name) for field_name in field_name_list] 278. if isinstance(field_list[0].rel, ManyToOneRel): ▼ Local vars Variable Value follow None obj_key '1' self <django.db.models.manipulators.ChangeManipulator object at 0xb6ed40cc> # /usr/local/lib/python2.4/site-packages/django/db/models/manipulators.py in __init__ 68. if self.follow.get(f.name, False): 69. self.fields.extend(f.get_manipulator_fields(self.opts, self, self.change)) 70. 71. # Add fields for related objects. 72. for f in self.opts.get_all_related_objects(): 73. if self.follow.get(f.name, False): 74. fol = self.follow[f.name] 75. self.fields.extend(f.get_manipulator_fields(self.opts, self, self.change, fol)) ... 76. 77. # Add field for ordering. 78. if self.change and self.opts.get_ordered_objects(): 79. self.fields.append(forms.CommaSeparatedIntegerField(field_name="order_")) 80. 81. def save(self, new_data): ▼ Local vars Variable Value f <RelatedObject: choice related to poll> fol {'position': True, 'votes': True, 'poll': False, 'id': True, 'choice': True} follow None self <django.db.models.manipulators.ChangeManipulator object at 0xb6ed40cc> # /usr/local/lib/python2.4/site-packages/django/db/models/related.py in get_manipulator_fields 112. 113. fields = [] 114. for i in range(count): 115. for f in self.opts.fields + self.opts.many_to_many: 116. if follow.get(f.name, False): 117. prefix = '%s.%d.' % (self.var_name, i) 118. fields.extend(f.get_manipulator_fields(self.opts, manipulator, change, 119. name_prefix=prefix, rel=True)) ... 120. return fields 121. 122. def __repr__(self): 123. return "<RelatedObject: %s related to %s>" % (self.name, self.field.name) 124. 125. def bind(self, field_mapping, original, bound_related_object_class=BoundRelatedObject): ▼ Local vars Variable Value attr <django.db.models.fields.related.RelatedManager object at 0xb6e75bac> change True count 5L f <django.db.models.fields.IntegerField object at 0xb6f2e40c> fields [FormField "choice.0.id"] follow {'position': True, 'votes': True, 'poll': False, 'id': True, 'choice': True} i 0 manipulator <django.db.models.manipulators.ChangeManipulator object at 0xb6ed40cc> opts <Options for Poll> prefix 'choice.0.' self <RelatedObject: choice related to poll> # /usr/local/lib/python2.4/site-packages/django/db/models/fields/__init__.py in get_manipulator_fields 224. rel is a boolean specifying whether this field is in a related context. 225. """ 226. field_objs, params = self.prepare_field_objs_and_params(manipulator, name_prefix) 227. 228. # Add the "unique" validator(s). 229. for field_name_list in opts.unique_together: 230. if field_name_list[0] == self.name: 231. params['validator_list'].append(getattr(manipulator, 'isUnique%s' % '_'.join(field_name_list))) ... 232. 233. # Add the "unique for..." validator(s). 234. if self.unique_for_date: 235. params['validator_list'].append(getattr(manipulator, 'isUnique%sFor%s' % (self.name, self.unique_for_date))) 236. if self.unique_for_month: 237. params['validator_list'].append(getattr(manipulator, 'isUnique%sFor%s' % (self.name, self.unique_for_month))) ▼ Local vars Variable Value change True field_name_list ('position', 'poll') field_objs [<class 'django.forms.IntegerField'>] follow True manipulator <django.db.models.manipulators.ChangeManipulator object at 0xb6ed40cc> name_prefix 'choice.0.' opts <Options for Choice> params {'validator_list': []} rel True self <django.db.models.fields.IntegerField object at 0xb6f2e40c>
comment:4 by , 18 years ago
Version: | magic-removal → SVN |
---|
Note:
See TracTickets
for help on using tickets.
A little bit more on that. Given this model:
1) this raise AttributeError: 'AddManipulator' object has no attribute 'isUniqueposition_poll'
when Poll.AddManager (or ChangeManager) instance is created (Yes, Poll, not Choice)
2) this don't, but is not taken into account, and lead to an integrity error if trying to add a duplicate entry
See also related tickets: #2415, #1751
Here is the traceback from case 1:
And here is the code around line 119 in db.models.related.py (get_manipulator_fields)
That's all for now. Hope this help!
--
didier