Problem with creating a one-to-one instance

16 views
Skip to first unread message

Carsten Fuchs

unread,
Apr 16, 2013, 11:50:13 AM4/16/13
to django...@googlegroups.com
Hi all,

I'm probably overlooking something very simple, but still cannot explain
what the code below does wrong:

With these models:

class Vorblendplan(models.Model):
# ...
pass

class Mitarbeiter(models.Model):
# ...
vbp = models.OneToOneField(Vorblendplan, null=True, blank=True,
on_delete=models.SET_NULL)

I try to make sure that a Mitarbeiter object has a proper (not None) vbp
instance. In the manage.py shell:

>>> ma = Mitarbeiter.objects.get(key="F426")
>>> ma.vbp # ok, initially "None"
>>> ma.vbp = Vorblendplan()
>>> ma.vbp.save()
>>> ma.save()

>>> ma = Mitarbeiter.objects.get(key="F426")
>>> ma.vbp # Why still "None"??

This, in contrast, works:

>>> ma = Mitarbeiter.objects.get(key="F426")
>>> ma.vbp # "None"
>>> v = Vorblendplan()
>>> v.save()
>>> ma.vbp = v
>>> ma.save()

>>> ma = Mitarbeiter.objects.get(key="F426")
>>> ma.vbp # ok, as expected
<Vorblendplan: Vorblendplan object>

Why does the first example not work?

Thank you very much, and best regards,
Carsten

Carsten Fuchs

unread,
Apr 25, 2013, 11:55:06 AM4/25/13
to django...@googlegroups.com
Hi all,

Am 16.04.2013 17:50, schrieb Carsten Fuchs:
> I'm probably overlooking something very simple, but still cannot explain
> what the code below does wrong: [...]
>
> >>> ma = Mitarbeiter.objects.get(key="F426")
> >>> ma.vbp # ok, initially "None"
> >>> ma.vbp = Vorblendplan()
> >>> ma.vbp.save()
> >>> ma.save()
>
> >>> ma = Mitarbeiter.objects.get(key="F426")
> >>> ma.vbp # Why still "None"??

I guess it's because the assignment

ma.vbp = Vorblendplan()

also updates ma.vbp_id (None), and is not updated in the subsequent

ma.vbp.save()

so that subsequently:

>>> ma.vbp.id
4741
>>> ma.vbp_id
# Still None


In the example that works (in my original mail, not quoted here), when
the assignment is done, the Vorblendplan instance already has an id, so
that it is properly carried into ma.vbp_id.

Can someone confirm this, is my understanding correct?

Best regards,
Carsten

Tom Evans

unread,
Apr 25, 2013, 12:53:25 PM4/25/13
to django...@googlegroups.com
On Thu, Apr 25, 2013 at 4:55 PM, Carsten Fuchs <carste...@cafu.de> wrote:
> Hi all,
> […]
> In the example that works (in my original mail, not quoted here), when the
> assignment is done, the Vorblendplan instance already has an id, so that it
> is properly carried into ma.vbp_id.
>
> Can someone confirm this, is my understanding correct?

Yes, this is correct, when you assign an object to a foreign key, it
must already be saved so that it has an id in order to persist in the
database. The code that does this is here:

https://github.com/django/django/blob/master/django/db/models/fields/related.py#L208

This is master, and you can see there is now a check in there - line
235 in master - that would have raised an exception in your example
(the check is also in 1.5).

In 1.4, the check is not present:

https://github.com/django/django/blob/stable/1.4.x/django/db/models/fields/related.py#L259

So I guess you're using 1.4!

Cheers

Tom

Carsten Fuchs

unread,
Apr 25, 2013, 2:48:18 PM4/25/13
to django...@googlegroups.com
Hi Tom,

Am 2013-04-25 18:53, schrieb Tom Evans:
> Yes, this is correct, when you assign an object to a foreign key, it
> must already be saved so that it has an id in order to persist in the
> database.

It's very good to hear this, thank you very much for your reply!

> In 1.4, the check is not present:
> https://github.com/django/django/blob/stable/1.4.x/django/db/models/fields/related.py#L259
> So I guess you're using 1.4!

No, I'm using 1.5.1 (sorry for not having mentioned this earlier), but didn't get any
exception, exactly as shown in my original mail.

Thanks to your pointers into the code, I tested a bit more, and it seems that my case is
not handled in class SingleRelatedObjectDescriptor, but in class
ReverseSingleRelatedObjectDescriptor -- which I don't understand, but can easily trigger
the assertion in line

https://github.com/django/django/blob/1.5.1/django/db/models/fields/related.py#L405

by a statement like ma.vbp = SomeOtherClass()

The __set__ method in ReverseSingleRelatedObjectDescriptor does not seem to have an
equivalent to the check in SingleRelatedObjectDescriptor, so this explains why I could
do the original assignment ma.vbp = Vorblendplan()

Best regards,
Carsten
Reply all
Reply to author
Forward
0 new messages