Django post_delete: подсчитать все объекты, у которых есть один соответствующий атрибут, с удаленным объектом

У меня есть настраиваемая функция, которая вызывается при удалении объекта заказов модели, для этого я использую post_delete.

Экземпляр модели «Заказы» всегда имеет «пользователь» ForeignKey. При удалении объекта модели «Заказы» я хочу проверить, есть ли другие экземпляры модели «Заказы» с тем же «пользователем».

def delete_reverse(sender, **kwargs):
try:
    if Orders.objects.filter(user__equal=kwargs['instance'].user).count() == 1:
        kwargs['instance'].user.delete()
    else:
        ...         
except:
    pass
post_delete.connect(delete_reverse, sender=Orders)

К сожалению, условие if не работает, т.е. оно неверно, даже если количество соответствующих записей должно быть 1. Видите ли вы какие-либо проблемы с моей функцией count ()?

Не используйте покрывало на кроватьexcept. Удалите его и посмотрите, не возникнет ли исключение. У меня есть идея, что __equal действительно нет существует.

Willem Van Onsem 13.09.2018 20:51

Более того, я считаю эту логику довольно странной. post_delete означает, что в момент чтоOrder уже удален, поэтому счетчик равен нулю (при отсутствии других заказов).

Willem Van Onsem 13.09.2018 20:52
1
2
238
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я думаю, что с этим кодом есть проблемы:

  1. Похоже, вы используете поиск в поле __equal, но этот поиск указывает на то, что нет существует в списке стандартные поля поиска [Django-doc], ближайшим из них является __exact, но, вероятно, здесь нет необходимости;

  2. вы используете "одеяло исключение" (!), это серьезный антипаттерн: если что-то выйдет из строя, то вы никогда не узнаете об этом. Как говорит Дзен Python: никогда не пропускайте исключения без звука, если они не отключены явно.

  3. Пост-удаление означает, что удаление уже произошло, следовательно, в этот момент экземпляра больше нет в базе данных, как указано в документация:

    Note that the object will no longer be in the database, so be very careful what you do with this instance.

Таким образом, последний элемент означает, что вы, вероятно, захотите проверить, равен ли счет нулю (следовательно, Order с этим user_id больше не существует):

@receiver(post_save, sender=Orders)
def delete_reverse(sender, instance, **kwargs):
    if not Order.objects.filter(user_id=instance.user_id).exists():
        instance.user.delete()

Однако обратите внимание, что даже в этом случае все еще существуют сценарии, в которых база данных может содержать User без каких-либо Order: например, когда мы меняем user_id для Order, тогда возможно, что у предыдущего пользователя больше нет, но эта функция будет не сработать. Так что, возможно, стоит периодически проверить базу данных на такие случаи.

Более того, я не знаю, удастся ли удалить User. Если это модель аутентификации в Django, это может привести к тому, что пользователь-администратор будет удален, если, например, случайно на его имя был поставлен заказ, а этот порядок будет удален позже. Более того, удаление пользователя может привести к большому количеству удалений (всех видов «сущностей», в которых участвует этот пользователь).

Note: a Django model normally has a singular name, so I adivce, like I did in the answer, to rename the Orders model to Order.

Спасибо за полезный ответ, отлично работает! В нашем случае пользователи должны быть удалены из-за политики конфиденциальности :)

schlaumi2001 13.09.2018 21:37

@ schlaumi2001: ну, я думаю, было бы лучше иметь какой-то флаг, который предотвращает удаление определенных пользователей (например, администраторов, сотрудников и т. д.)

Willem Van Onsem 13.09.2018 21:43

Другие вопросы по теме