#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 , 17 years ago
| milestone: | 1.0 beta → 1.0 |
|---|---|
| Triage Stage: | Unreviewed → Accepted |
comment:2 by , 17 years ago
| Cc: | added |
|---|
comment:3 by , 17 years ago
| Cc: | added |
|---|
comment:4 by , 17 years ago
I found that 'content_object' is not in TaggedItem.__dict__, missing due to inheritance?
comment:5 by , 17 years ago
| Cc: | added |
|---|
comment:6 by , 17 years ago
| Owner: | changed from to |
|---|
comment:7 by , 17 years ago
| Status: | new → assigned |
|---|
comment:8 by , 17 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 , 17 years ago
| Attachment: | genericforeignkey_fail_in_abstract_models_r8507.diff added |
|---|
Patch that fixes problem (with tests)
comment:9 by , 17 years ago
| Has patch: | set |
|---|
comment:11 by , 17 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 , 17 years ago
| Cc: | added |
|---|
comment:13 by , 17 years ago
| Owner: | changed from to |
|---|---|
| Status: | assigned → new |
comment:14 by , 17 years ago
| Status: | new → assigned |
|---|
comment:15 by , 17 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.