#18599: GenericForeignKey field can't be set on init of model
--------------------------------------+------------------------------------
     Reporter:  dpantele              |                    Owner:  nobody
         Type:  Bug                   |                   Status:  new
    Component:  contrib.contenttypes  |                  Version:  1.4
     Severity:  Normal                |               Resolution:
     Keywords:                        |             Triage Stage:  Accepted
    Has patch:  0                     |      Needs documentation:  0
  Needs tests:  0                     |  Patch needs improvement:  0
Easy pickings:  0                     |                    UI/UX:  0
--------------------------------------+------------------------------------
Changes (by aaugustin):

 * stage:  Unreviewed => Accepted


Comment:

 The cause is very simple:
 
[https://github.com/django/django/blob/master/django/contrib/contenttypes/generic.py#L44
 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:
 {{{
 >>> a = A()
 >>> b = B(obj=a)
 >>> b.obj
 >>> b.content_type
 <ContentType: a>
 >>> b.object_id
 >>> b.save()
 Traceback (most recent call last):
   File "<console>", line 1, in <module>
   File "/Users/myk/Documents/dev/django-trunk/django/db/models/base.py",
 line 479, in save
     force_update=force_update, update_fields=update_fields)
   File "/Users/myk/Documents/dev/django-trunk/django/db/models/base.py",
 line 574, in save_base
     result = manager._insert([self], fields=fields, return_id=update_pk,
 using=using, raw=raw)
   File "/Users/myk/Documents/dev/django-
 trunk/django/db/models/manager.py", line 203, in _insert
     return insert_query(self.model, objs, fields, **kwargs)
   File "/Users/myk/Documents/dev/django-trunk/django/db/models/query.py",
 line 1589, in insert_query
     return query.get_compiler(using=using).execute_sql(return_id)
   File "/Users/myk/Documents/dev/django-
 trunk/django/db/models/sql/compiler.py", line 914, in execute_sql
     cursor.execute(sql, params)
   File "/Users/myk/Documents/dev/django-trunk/django/db/backends/util.py",
 line 42, in execute
     return self.cursor.execute(sql, params)
   File "/Users/myk/Documents/dev/django-
 trunk/django/db/backends/sqlite3/base.py", line 340, in execute
     return Database.Cursor.execute(self, query, params)
 IntegrityError: test_app_b.object_id may not be NULL
 }}}

 In comparison here's what happens with a regular FK:

 {{{
 >>> a = A()
 >>> b = B(fk=a)
 >>> b.fk
 <A: A object>
 >>> b.save()
 Traceback (most recent call last):
   File "<console>", line 1, in <module>
   File "/Users/myk/Documents/dev/django-trunk/django/db/models/base.py",
 line 479, in save
     force_update=force_update, update_fields=update_fields)
   File "/Users/myk/Documents/dev/django-trunk/django/db/models/base.py",
 line 574, in save_base
     result = manager._insert([self], fields=fields, return_id=update_pk,
 using=using, raw=raw)
   File "/Users/myk/Documents/dev/django-
 trunk/django/db/models/manager.py", line 203, in _insert
     return insert_query(self.model, objs, fields, **kwargs)
   File "/Users/myk/Documents/dev/django-trunk/django/db/models/query.py",
 line 1589, in insert_query
     return query.get_compiler(using=using).execute_sql(return_id)
   File "/Users/myk/Documents/dev/django-
 trunk/django/db/models/sql/compiler.py", line 914, in execute_sql
     cursor.execute(sql, params)
   File "/Users/myk/Documents/dev/django-trunk/django/db/backends/util.py",
 line 42, in execute
     return self.cursor.execute(sql, params)
   File "/Users/myk/Documents/dev/django-
 trunk/django/db/backends/sqlite3/base.py", line 340, in execute
     return Database.Cursor.execute(self, query, params)
 IntegrityError: test_app_b.fk_id may not be NULL
 }}}

 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.

-- 
Ticket URL: <https://code.djangoproject.com/ticket/18599#comment:2>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/django-updates?hl=en.

Reply via email to