Opened 12 years ago
Closed 9 years ago
#18599 closed Bug (fixed)
GenericForeignKey field can't be set on init of model
Reported by: | dpantele | Owned by: | nobody |
---|---|---|---|
Component: | contrib.contenttypes | Version: | 1.4 |
Severity: | Normal | Keywords: | |
Cc: | dpantele | Triage Stage: | Accepted |
Has patch: | yes | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
If we are trying to set GenericForeignKey to non-saved object during model initialization, it is not set.
For example:
class A(models.model): pass class B(models.model): object_id = models.PositiveIntegerField() content_type = models.ForeignKey(ContentType) obj = generic.GenericForeignKey() ... a = A() b = B(obj=a) b.obj # None b.obj.save() # 'NoneType' object has no attribute 'save'
Attachments (1)
Change History (9)
comment:1 by , 12 years ago
Summary: | GenericForeignKey field can't be set on init of moel → GenericForeignKey field can't be set on init of model |
---|
comment:2 by , 12 years ago
Triage Stage: | Unreviewed → Accepted |
---|
comment:3 by , 12 years ago
Cc: | added |
---|
It is very strange that any object which is passed to the constructor is thrown away. In FK situation I can do like that:
>>> a = A() >>> b = B(fk=a) >>> b.fk.save() >>> b.fk_id = b.fk.id >>> b.save()
In the GFK situation it is not possible for me to save b object if i don't pass a. So, I should everywhere pass two references or use an explicit notation:
>>> a = A() >>> b = B() >>> b.gfk = a >>> b.gfk.save() >>> b.gfk = b.gfk >>> b.save()
Of course, it should be possible to keep reference to non-saved object. For example, I need to validate object 'b', and if it is not valid, I should not save 'a' object at all.
I see very simple way of solving this problem: we should keep cached object not in object instance, but in the field instance.
by , 11 years ago
Attachment: | 18599-test.patch added |
---|
comment:5 by , 11 years ago
See also #16508, as this is a common problem of virtual fields (implementation of GenericForeignKey).
comment:6 by , 9 years ago
Has patch: | set |
---|
This was fixed in 8a47ba679d2da0dee74671a53ba0cd918b433e34. PR to add the test.
comment:8 by , 9 years ago
Resolution: | → fixed |
---|---|
Status: | new → closed |
The cause is very simple: GenericForeignKey.instance_pre_init extracts the content-type and the id of the related object and then throws the object itself away. If an unsaved object is passed in the constructor, its id is None, so the pointer to the object is lost at this point.
Here's what happens with a GFK:
In comparison here's what happens with a regular FK:
In both cases, saving the B object will fail because the A object doesn't have an id yet, so there isn't much to gain in "fixing" this.
We should probably just raise an exception in this situation.