Django - каскад при другом условии - PullRequest
0 голосов
/ 29 апреля 2020

Я использую Django и базу данных Postgres, и у меня есть две таблицы (Авторы, Книги).

Я не хочу разрешать удаление каких-либо записей, вместо того, чтобы изменить логическое значение невидимого поля, называемого «активным» - поле, которое есть в обеих таблицах. Я хотел бы, чтобы пользователь изменил «активное» поле автора на «Ложь», во всех книгах с FK этого автора в таблице «Книги» их «активное» поле также установлено на «Ложь».

В Django, мои единственные опции, которые, кажется, связаны с удалением, как бы я настроил это с файлом models.py?

1 Ответ

1 голос
/ 29 апреля 2020

Вы можете решить это с помощью сигналов . В следующем примере я предполагаю, что ваша модель 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()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...