Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I prefetch_related across a reverse one-to-one relationship where the one-to-one relationship may be different?

Tags:

python

sql

django

Let's say I have a database with Movies, Books, and Software, and they all inherit a single Item model.

class Item(models.Model):
    ...

class Movie(models.Model):
    item = models.OneToOneField(Item)
    ...

class Book(models.Model):
    item = models.OneToOneField(Item)
    ...

class Software(models.Model):
    item = models.OneToOneField(Item)
    ...

Now I want to make a database query on Item but I want to pick up the related object to that item, whether it be a Movie, Book, or Software. If all the items were one type, say, Movies, then I could do the following:

Item.objects.prefetch_related('movie')

However, I need to be able to fetch the related object no matter what type it is. Can I run:

Item.objects.prefetch_related('movie', 'book', 'software')

Will this find the related object no matter what type it is, and will this be efficient? Is there a better way of doing this?

like image 874
ArKi Avatar asked Apr 20 '12 22:04

ArKi


1 Answers

I'll suppose the OneToOneFields have related_name set as your QuerySet examples indicate, that is, 'movie', 'book' and 'software' respectively.

To traverse a one-to-one relationship backwards you don't need prefetch_related, this is something that is easy to achieve with a LEFT OUTER JOIN automatically generated by select_related. That means, you should be able to do

Item.objects.select_related('movie', 'book', 'software')

and each returned Item instance will automatically contain a cached instance of the corresponding Movie, Book and Software (if there is one, of course).

prefetch_related is only needed when you want to avoid an O(N) query issue with many-to-many or many-to-one relationships, that is, with a ManyToManyField or a reverse traversal of ForeignKey.

like image 55
koniiiik Avatar answered Nov 17 '22 07:11

koniiiik