Opened 19 years ago
Closed 18 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 , 19 years ago
comment:2 by , 19 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