#8309 closed (fixed)
GenericForeignKey fails when used in abstract base models
Reported by: | Wonlay | Owned by: | Jacob |
---|---|---|---|
Component: | Contrib apps | Version: | dev |
Severity: | Keywords: | GenericForeignKey, model inheritance | |
Cc: | carl@…, wonlay@…, albrecht.andi@…, gonz@… | Triage Stage: | Accepted |
Has patch: | yes | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
The following code will reproduce this bug:
# aaa/models.py from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes import generic class MyModel(models.Model): field = models.IntegerField() class TaggedItemBase(models.Model): class Meta: abstract = True content_type = models.ForeignKey(ContentType) object_id = models.PositiveIntegerField() content_object = generic.GenericForeignKey() class TaggedItem(TaggedItemBase): """A tag on an item.""" tag = models.SlugField() class Meta: ordering = ["tag"] def __unicode__(self): return self.tag # From command shell >>> from aaa.models import MyModel, TaggedItem >>> m = MyModel(field=1) >>> m.save() >>> t = TaggedItem(content_object=m, tag="my") Traceback (most recent call last): File "<console>", line 1, in ? File "/usr/lib/python2.4/site-packages/django/db/models/base.py", line 240, in __init__ raise TypeError, "'%s' is an invalid keyword argument for this function" % kwargs.keys()[0] TypeError: 'content_object' is an invalid keyword argument for this function
If we do not use model inheritance, the script works fine.
Attachments (1)
Change History (17)
comment:1 by , 16 years ago
milestone: | 1.0 beta → 1.0 |
---|---|
Triage Stage: | Unreviewed → Accepted |
comment:2 by , 16 years ago
Cc: | added |
---|
comment:3 by , 16 years ago
Cc: | added |
---|
comment:4 by , 16 years ago
I found that 'content_object' is not in TaggedItem.__dict__
, missing due to inheritance?
comment:5 by , 16 years ago
Cc: | added |
---|
comment:6 by , 16 years ago
Owner: | changed from | to
---|
comment:7 by , 16 years ago
Status: | new → assigned |
---|
comment:8 by , 16 years ago
Real problem is in this fragment of django.db.base.ModelBase
class:
# The abstract base class case. names = set([f.name for f in new_class._meta.local_fields + new_class._meta.many_to_many]) for field in base._meta.local_fields + base._meta.local_many_to_many: if field.name in names: raise FieldError('Local field %r in class %r clashes with field of similar name from abstract base class %r' % (field.name, name, base.__name__)) new_class.add_to_class(field.name, copy.deepcopy(field))
The problem is django.contrib.generic.GenericForeignKey.contribute_to_class
doesnt call to cls._meta.add_field(self)
, that insert field into base._meta.local_fields
.
But the thing is GenericForeignKey
is not a real field... is a virtual field. I'll try take a workaround that also implements a new feature, for adding virtual fields thats follow inheritance.
by , 16 years ago
Attachment: | genericforeignkey_fail_in_abstract_models_r8507.diff added |
---|
Patch that fixes problem (with tests)
comment:9 by , 16 years ago
Has patch: | set |
---|
comment:11 by , 16 years ago
I'm not a core dev, I think patch works and of course pass all model tests. If a core developer think patch is good, he will check in as soon as possible (it's scheduled for 1.0)
comment:12 by , 16 years ago
Cc: | added |
---|
comment:13 by , 16 years ago
Owner: | changed from | to
---|---|
Status: | assigned → new |
comment:14 by , 16 years ago
Status: | new → assigned |
---|
comment:15 by , 16 years ago
Resolution: | → fixed |
---|---|
Status: | assigned → closed |
It may caused by:
GenericForeignKey.contribute_to_class is called on TaggedItemBase(not on TaggedItem), and register a signal pre_init.
When initialize the subclass TaggedItem, the signal does not fire.