OneToOne and related models

209 views
Skip to first unread message

alex finn

unread,
Jul 14, 2008, 4:05:00 PM7/14/08
to Django developers
Hi Everybody,

I need some assistance on django's OneToOne mapping implementation.
Several days ago I started a discussion in django-users but didn't get
too much of feedback :(
Here it is: http://groups.google.com/group/django-users/browse_thread/thread/8b30b3bdc157e2ba/5102e779805b0510#5102e779805b0510

Briefly, the issue is that when I'm using multiple OneToOne mappings
in one model and then delete an instance of this model, objects
associated with it as OneToOne are not being deleted. I even opened a
ticket for that (http://code.djangoproject.com/ticket/7708) but again
didn't see any activity around it. So I decided to look into it myself
and try to resolve it, but unfortunately I don't have enough django
and especially python experience (I'm mostly used to C/Java/PHP) to
fix it on my own.

While looking into the problem I found out that these relationships
don't appear in models _meta._related_objects_cache
Now I'm having difficulties trying to understand how this cache is
being built as according to Options._fill_related_objects_cache it
should be filled in with parent models only. But it definitely
contains the ManyToOne relationships (ForeignKeys). Could anyone
please explain me how this part of the ORM is working?

Thanks,
Alex.

alex finn

unread,
Jul 15, 2008, 5:20:14 AM7/15/08
to Django developers
Here's the code example that shows the issue:
models.py: http://dpaste.com/65040/
tests.py: http://dpaste.com/65041/
This test fails as Place instance was not deleted

Michael Glassford

unread,
Jul 15, 2008, 10:22:29 AM7/15/08
to django-d...@googlegroups.com
alex finn wrote:
> Hi Everybody,
>
> I need some assistance on django's OneToOne mapping implementation.
> Several days ago I started a discussion in django-users but didn't get
> too much of feedback :(
> Here it is: http://groups.google.com/group/django-users/browse_thread/thread/8b30b3bdc157e2ba/5102e779805b0510#5102e779805b0510
>
> Briefly, the issue is that when I'm using multiple OneToOne mappings
> in one model and then delete an instance of this model, objects
> associated with it as OneToOne are not being deleted. I even opened a
> ticket for that (http://code.djangoproject.com/ticket/7708) but again
> didn't see any activity around it. So I decided to look into it myself
> and try to resolve it, but unfortunately I don't have enough django
> and especially python experience (I'm mostly used to C/Java/PHP) to
> fix it on my own.

I don't know if you discovered this yet, but the delete is working in
one direction, but not in the direction you're expecting it to. For
instance, using the models you posted in another message:

class Place(models.Model):
name = models.CharField(max_length = 100)

class Restaurant(models.Model):
place = models.OneToOneField(Place, primary_key=True)

If you create a Place and a Restaurant that is linked to it, deleting
the Restaurant will not delete the Place (this is the problem you're
reporting here), but deleting the Place will delete the Restaurant.

I'm not sure this was an intentional Django design decision or not, and
I can see why you expect it to work differently. However, there is also
some rationale for it working the way that it does.

1) For example, if I extend your model to include:

class GasStation(models.Model):
place = models.OneToOneField(Place, primary_key=True)

If I have a Place that is both a Restaurant and a GasStation, then
decide to close its GasStation but keep the Restaurant open, I would
delete the GasStation object but expect the Place and the Restaurant to
remain--which is, in fact, what happens.

2) This behavior of Django's OneToOneField is consistent with the
behavior of its ForeignKey field: the model containing the OneToOneField
or the ForeignKey field is deleted if the model it points to is deleted,
but not the other way around. (In fact, if you look at the definition of
the OneToOneField class, it turns out that it is actually just a
subclass of ForeignKey class, so this isn't surprising).

> While looking into the problem I found out that these relationships
> don't appear in models _meta._related_objects_cache

Consistent with the behavior I described above, it's true that, as you
say, the Place doesn't appear in the Restaurant's
_meta._related_objects_cache collection; however, the Restauraunt *does*
appear in the Place's _meta._related_objects_cache collection.


> Now I'm having difficulties trying to understand how this cache is
> being built as according to Options._fill_related_objects_cache it
> should be filled in with parent models only. But it definitely
> contains the ManyToOne relationships (ForeignKeys). Could anyone

> please explain me how this part of the ORM is working?\

Hope this helps.


Mike

Michael Glassford

unread,
Jul 15, 2008, 10:22:29 AM7/15/08
to public-django-developer...@hugh.gmane.org

alex finn wrote:
> Hi Everybody,
>
> I need some assistance on django's OneToOne mapping implementation.
> Several days ago I started a discussion in django-users but didn't get
> too much of feedback :(
> Here it is: http://groups.google.com/group/django-users/browse_thread/thread/8b30b3bdc157e2ba/5102e779805b0510#5102e779805b0510
>
> Briefly, the issue is that when I'm using multiple OneToOne mappings
> in one model and then delete an instance of this model, objects
> associated with it as OneToOne are not being deleted. I even opened a
> ticket for that (http://code.djangoproject.com/ticket/7708) but again
> didn't see any activity around it. So I decided to look into it myself
> and try to resolve it, but unfortunately I don't have enough django
> and especially python experience (I'm mostly used to C/Java/PHP) to
> fix it on my own.

I don't know if you discovered this yet, but the delete is working in

> While looking into the problem I found out that these relationships


> don't appear in models _meta._related_objects_cache

Consistent with the behavior I described above, it's true that, as you

say, the Place doesn't appear in the Restaurant's
_meta._related_objects_cache collection; however, the Restauraunt *does*
appear in the Place's _meta._related_objects_cache collection.

> Now I'm having difficulties trying to understand how this cache is
> being built as according to Options._fill_related_objects_cache it
> should be filled in with parent models only. But it definitely
> contains the ManyToOne relationships (ForeignKeys). Could anyone

> please explain me how this part of the ORM is working?\

Hope this helps.


Mike

alex finn

unread,
Jul 15, 2008, 10:59:53 AM7/15/08
to Django developers
Hi Mike,

thanks, this really helps and makes complete sense.
In this case, could it be a feature request for django to implement
bidirectional delete for related models in OneToOne case?
It is not a complex thing for me to override delete method for the
model and thus get the bidirectional delete, but when you call delete
method on a QuerySet it won't invoke customized delete method and thus
I will need to make sure related OneToOne instances are deleted as
well on my own.

Thanks again,
Alex.

Michael Glassford

unread,
Jul 15, 2008, 11:30:48 AM7/15/08
to django-d...@googlegroups.com
alex finn wrote:
> Hi Mike,
>
> thanks, this really helps and makes complete sense.
> In this case, could it be a feature request for django to implement
> bidirectional delete for related models in OneToOne case?

I'm not officially connected to the Django project in any way, so you
can make such a request as easily as I can. Why not open a new ticket or
add the request to the one you created before at
http://code.djangoproject.com/ticket/7708?

Michael Glassford

unread,
Jul 15, 2008, 11:30:48 AM7/15/08
to public-django-developer...@hugh.gmane.org

alex finn wrote:
> Hi Mike,
>
> thanks, this really helps and makes complete sense.
> In this case, could it be a feature request for django to implement
> bidirectional delete for related models in OneToOne case?

I'm not officially connected to the Django project in any way, so you

can make such a request as easily as I can. Why not open a new ticket or
add the request to the one you created before at
http://code.djangoproject.com/ticket/7708?

> It is not a complex thing for me to override delete method for the

Reply all
Reply to author
Forward
0 new messages