Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django, update the object after a prefetch_related

I have the following models:

class Publisher(models.Model):
    name = models.CharField(max_length=30)


class Book(models.Model):
    title = models.CharField(max_length=100)
    publisher = models.ForeignKey(Publisher)

In my views.py, When I want to show the publisher page, I also want to show their books, so I usually do something like this:

publisher = Publisher.objects.prefetch_related('book_set').filter(pk=id).first()

Then, after some processing I also do some work with the books

for book in publisher.book_set.all():
    foo()

This works great, but I have one problem. If there is a book added between the query and the for loop, the publisher.book_set.all() won't have the newly added books because it was prefetched.

Is there a way to update the publisher object?

like image 244
Dalvtor Avatar asked Jan 05 '18 07:01

Dalvtor


People also ask

What's the difference between Select_related and Prefetch_related in Django ORM?

select_related() “follows” foreign-key relationships, selecting additional related-object data when it executes its query. prefetch_related() does a separate lookup for each relationship and does the “joining” in Python.

What does Select_related do in Django?

Django offers a QuerySet method called select_related() that allows you to retrieve related objects for one-to-many relationships. This translates to a single, more complex QuerySet, but you avoid additional queries when accessing the related objects. The select_related method is for ForeignKey and OneToOne fields.

Why are QuerySets considered lazy?

This is because a Django QuerySet is a lazy object. It contains all of the information it needs to populate itself from the database, but will not actually do so until the information is needed.


2 Answers

You can delete the entire prefetch cache on the instance:

if hasattr(publisher, '_prefetched_objects_cache'):
    del publisher._prefetched_objects_cache

If you only want to delete a particular prefetched relation:

if hasattr(publisher, '_prefetched_objects_cache'):
    publisher._prefetched_objects_cache.pop('book_set', None)
like image 66
user2390182 Avatar answered Oct 26 '22 18:10

user2390182


Also there is possibility to drop all prefetch_related from Django doc:

To clear any prefetch_related behavior, pass None as a parameter::

non_prefetched = qs.prefetch_related(None)

like image 40
valex Avatar answered Oct 26 '22 18:10

valex