Вы можете решить это с помощью сигналов . В следующем примере я предполагаю, что ваша модель Book
имеет поле внешнего ключа, которое выглядит следующим образом.
class Book(models.Model):
...
author = models.ForeignKey("Author", related_name="books")
...
Вариант 1. Использовать сигналы
Пример функции, подключенной к Author
post_save
сигнал.
from django.db import transaction
from django.db.models.signals import post_save
def update_books_status(sender, instance, created, **kwargs):
with transaction.atomic():
books = Books.objects.select_for_update().filter(author=instance)
for book in books:
book.active = False
book.save()
post_save.connect(update_books_status, sender=Author)
В этом примере транзакция atomi c гарантирует, что все обновления выполняются в одном запросе к БД. Это избавит вас от проблемы n+1
, которая возникла бы, если бы вы только что выполнили набор запросов в for
l oop.
Вариант 2. Переопределите save()
Другой способ справиться с этим, который, вероятно, лучше, это переопределить метод Author
модель save()
.
class Author(models.Model):
...
def save(self, *args, **kwargs):
# Make sure we are not saving a new Author
# And we are saving the Author as inactive
# And we are are saving an Author that was active.
if not self._state.adding and not self.active and self._loaded_values['active']:
self.inactivate_books()
super().save(*args, **kwargs)
def inactivate_books(self):
with transaction.atomic():
books = Books.objects.select_for_update().filter(author=self)
for book in books:
book.active = False
book.save()