简体   繁体   中英

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?

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)

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)

There's a nicer way to clear prefetched attributes, using only public Django APIs, which is the refresh_from_db() method :

# Reloads all fields from the object as well as clearing prefetched attributes
publisher.refresh_from_db()
# Clears one prefetched attribute, will be re-fetched on next access
publisher.refresh_from_db(fields=['book_set'])

for book in publisher.book_set.all():

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM