Opened 16 years ago

Closed 16 years ago

Last modified 13 years ago

#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)

genericforeignkey_fail_in_abstract_models_r8507.diff (4.9 KB ) - added by Manuel Saelices 16 years ago.
Patch that fixes problem (with tests)

Download all attachments as: .zip

Change History (17)

comment:1 by Malcolm Tredinnick, 16 years ago

milestone: 1.0 beta1.0
Triage Stage: UnreviewedAccepted

comment:2 by Carl Meyer, 16 years ago

Cc: carl@… added

comment:3 by Wonlay, 16 years ago

Cc: wonlay@… added

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.

comment:4 by Wonlay, 16 years ago

I found that 'content_object' is not in TaggedItem.__dict__, missing due to inheritance?

comment:5 by Andi Albrecht, 16 years ago

Cc: albrecht.andi@… added

comment:6 by Manuel Saelices, 16 years ago

Owner: changed from nobody to Manuel Saelices

comment:7 by Manuel Saelices, 16 years ago

Status: newassigned

comment:8 by Manuel Saelices, 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 Manuel Saelices, 16 years ago

Patch that fixes problem (with tests)

comment:9 by Manuel Saelices, 16 years ago

Has patch: set

comment:10 by anonymous, 16 years ago

msaelices's patch works fine for me?
Is it time to check in?

comment:11 by Manuel Saelices, 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 anonymous, 16 years ago

Cc: gonz@… added

comment:13 by Jacob, 16 years ago

Owner: changed from Manuel Saelices to Jacob
Status: assignednew

comment:14 by Jacob, 16 years ago

Status: newassigned

comment:15 by Jacob, 16 years ago

Resolution: fixed
Status: assignedclosed

(In [8855]) Fixed #8309: subclasses now inherit GenericForeignKey correctly. There's also now an internal API so that other "virtual fields" like GFK can be inherited as well. Thanks, msaelices.

comment:16 by Jacob, 13 years ago

milestone: 1.0

Milestone 1.0 deleted

Note: See TracTickets for help on using tickets.
Back to Top