Каскадное соглашение Django OneToOneField on_delete

#django #postgresql #foreign-keys #django-3.1

#django #postgresql #внешние ключи #django-3.1

Вопрос:

У меня есть эти модели в моем коде

 class Address(models.Model):
    street = models.CharField(max_length=50)
    city = models.CharField(max_length=10)

class User(models.Model):
    name = models.CharField(max_length=20)
    age = models.IntegerField()
    address = models.OneToOneField(Address, on_delete=models.CASCADE)
  

Я понимаю, как models.CASCADE работает в Django. Если я удалю Address запись, соответствующая User запись будет удалена, но это не то, что я хочу. Я хочу, чтобы Address запись была удалена, если User запись будет удалена.

Я знаю, что могу добиться этого, поместив OneToOneField в Address вместо User , но для меня это не имеет смысла с точки зрения схемы базы данных, потому что User имеет Address . У Address нет User .

Я пытался найти информацию о том, как принудительно выполнить удаление обратным способом, но, по-видимому, это невозможно из всех опций, которые есть в Django (https://docs.djangoproject.com/en/3.1/ref/models/fields/#django.db.models .ForeignKey.on_delete).

Кто-нибудь знает альтернативу? Или правильный способ построения схемы базы данных в противном случае?

Спасибо!

Комментарии:

1. возможно, pre_delete сигнал?

2. @ArakkalAbu — хорошо, спасибо. это кажется хорошей идеей, хотя я чувствую, что немного странно иметь on_delete функциональность, но не использовать ее в любом случае. Я также хотел знать, как я могу защитить User от удаления, если Address будет удален. Должен ли я просто использовать on_delete=models.PROTECT ?

Ответ №1:

Я не знаю, как указать в вашем уровне запутывания (orm), но на уровне базы данных вы указываете что-то вроде

 ,constraint usr2adr_fk
            foreign key (adr_id)
            references address(id)
            on delete set null         --<<< instead of delete
  

К вашему сведению, всего пара комментариев:

  • отношения 1: 1 всегда сомнительны. Иногда по соображениям безопасности или если вы проводите значительный анализ одного из столбцов. Но в противном случае просто переместите столбец из дочерней таблицы в родительскую. Кроме того, на уровне базы данных их очень сложно реализовать. Вам нужны двунаправленные FKS и ограничение уникальности столбца.
  • Возраст — очень плохой атрибут. Оно меняется ежегодно, поэтому вам нужно обновление, чтобы поддерживать его в актуальном состоянии, но не все они меняются одновременно. Гораздо лучше хранить дату рождения, а затем вычислять возраст, когда это необходимо. Обновление не требуется.

Комментарии:

1. Спасибо. Я должен сказать, что модели — это просто глупые шаблоны, иллюстрирующие проблему, с которой я столкнулся с гораздо большими таблицами. age это просто то, что я ввел случайным образом, но я понял ваш первый пункт.

Ответ №2:

Согласно документам, on_delete=models.CASCADE не будет удалять связанный объект ( OneToOneField например.), и такие сигналы, как pre_delete и post_delete , должны использоваться для имитации поведения