Почему «on_delete = models.CASCADE» моей модели не создает каскадное ограничение внешнего ключа? - PullRequest
0 голосов
/ 15 января 2019

Я использую Django, Python 3.7 и PostgreSQL 9.5. Как мне разметить мою модель таким образом, чтобы генерировалось каскадное ограничение внешнего ключа? В настоящее время у меня есть это в моем файле models.py ...

class ArticleStat(models.Model):
    article = models.ForeignKey(Article, on_delete=models.CASCADE, )

Когда я запускаю make migrations my_project в консоли управления, он создает файл, содержащий это ...

    migrations.CreateModel(
        name='ArticleStat',
        fields=[
            ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
            ...
            ('article', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='my_project.Article')),
        ],
    ),

Однако, когда я запускаю миграцию (используя migrate my_project 0001), полученный внешний ключ не содержит ограничения каскадного удаления. Вот как выглядит описание в PostgreSQL ...

"my_project_articlesta_article_id_a02a5add_fk_my_project" FOREIGN KEY (article_id) REFERENCES my_project_article(id) DEFERRABLE INITIALLY DEFERRED

Как еще можно получить мой файл models.py для вывода ограничения каскадного удаления внешнего ключа?

1 Ответ

0 голосов
/ 16 января 2019

Как описано в документации django ForeignKey, django просто эмулирует это поведение, а не откладывает его в базу данных.

Django эмулирует поведение ограничения SQL ON DELETE CASCADE, а также удаляет объект, содержащий ForeignKey.

Итак, чтобы ответить на ваш вопрос: это ожидаемое поведение и все равно будет работать так же, как вы ожидаете, что оно будет работать на уровне базы данных.

Как еще можно получить мой файл models.py для вывода ограничения каскадного удаления внешнего ключа?

Вы не можете, так как в настоящее время django не поддерживает эту функцию. Однако есть билет, обсуждающий добавление: https://code.djangoproject.com/ticket/21961


Изменить для дальнейшего разъяснения о том, как применять это на уровне базы данных

Хотя я настоятельно рекомендую просто позволить django справиться с этим для вас, могут быть причины не делать этого.

Чтобы отказаться от операций по созданию или удалению таблицы базы данных, вы можете установить Options.managed в False в Meta классе ArticleStat. Это, однако, также означает, что вы теперь несете ответственность за ручную миграцию, например, написание оператора CREATE TABLE для определения таблицы, включающей ограничение внешнего ключа (которое теперь у вас есть полный контроль). Еще одно соображение, которое следует принять во внимание, заключается в том, что вы должны дать указание django больше ничего не делать при удалении объекта Article, на который есть ссылка (поскольку теперь за это отвечает ваша база данных). Это можно обеспечить, установив on_delete в models.DO_NOTHING .

Соберите ваш ArticleStat теперь будет выглядеть так:

class ArticleStat(models.Model):
    article = models.ForeignKey(Article, on_delete=models.DO_NOTHING)

    class Meta:
        managed = False

Комментарий о сигналах побудил меня вернуться к этому и перечислить некоторые подводные камни для рассмотрения.

  • Отказ означает также отказ от сигналов Джанго. В частности pre_delete и post_delete больше не будут запускаться для каскадных объектов.

  • Как упомянуто в описании билета смешивание базы данных и django-каскадирование не будут хорошо сочетаться.

    Если модель A ссылается на модель B, используя CASCADE_DB, но модель B ссылается на модель C, используя обычный CASCADE, удаление A не будет каскад весь путь до C.

При этом я не смог найти какое-либо определенное доказательство того, почему django ведет себя так, как в настоящее время.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...