Невозможно удалить элементы из базы данных Django sqlite3 с ошибкой «ограничение внешнего ключа не удалось» - PullRequest
2 голосов
/ 29 апреля 2019

Есть некоторые элементы, которые нельзя удалить или изменить из моей базы данных Django sqlite3.При попытке удалить эти элементы я получаю integrity error: foreign key constraint failed.

. Разочаровывает то, что это не так с большинством элементов в моей базе данных.Я считаю, что это влияет только на несколько рядов, которые я должен был создать, прежде чем вносить некоторые изменения в модели.Я не помню, какие именно изменения я внес в файл models.py, но я не думаю, что это было что-то радикальное.У меня нет информации о выполненных миграциях, потому что я удалил эти файлы, думая, что это может решить проблему.

Я включил пример того, как в настоящее время настраиваются классы в models.py.Ничего сложного, стандартные модели с простым внешним ключом, который даже не является обязательным полем.

Я пытался редактировать файлы миграции, полностью удаляя историю миграции, редактируя модели с помощью models.py.

models.py:

class ExampleOne(models.Models):
    title = model.CharField(max_length=500, null=True, blank=True)

class ExampleTwo(models.Models):
    title = model.CharField(max_length=500, null=True, blank=True)
    example_one = models.ForeignKey(ExampleOne, null=True, blank=True, on_delete=models.CASCADE)

Я бы не хотел удалять файл моей базы данных.Я мог бы удалить эти экземпляры exampleone и exampletwo, но когда я пытаюсь удалить любой элемент, созданный до того, как настроил файлы модели, я получаю сообщение об ошибке:

django.db.utils.IntegrityError: FOREIGN KEY constraint failed

Ответы [ 2 ]

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

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

$ python
> import sqlite3
> conn = sqlite3.connect(name_of_db_file.sqlite3)
> cur = conn.cursor()
> cur.execute("DELETE FROM appname_exampletwo WHERE appname_exampleone_id='[id of undeletable item]'")
> conn.commit()
> conn.close()

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

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

django.db.utils.IntegrityError: The row in table 'appname_exampleone_exampletwos' with primary key '[some_int]' has an invalid foreign key: appname_exampleone_exampletwos.exampletwo_id contains a value '[some_other_int}' that does not have a corresponding value in appname_exampletwo.id.

Это заставило меня немного нервничать, но я прошел и удалил проблемные строки в этой реляционной таблице:

> cur.execute("SELECT * FROM appname_exampleone_exampletwos WHERE id='[some_int]'")

В конечном итоге все выглядит хорошо.

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

Это потому, что вы упускаете on_delete в ForeignKey, это обязательно в новой версии Django.

Добавьте следующее on_delete в соответствии с вашим приложением, внесите изменения и повторите миграцию.Тогда все должно быть в порядке.

Из документа: https://docs.djangoproject.com/en/2.2/ref/models/fields/#arguments

ForeignKey принимает другие аргументы, определяющие детали работы отношения.

ForeignKey.on_delete

Когда объект, на который ссылается ForeignKey, удаляется, Django будет эмулировать поведение ограничения SQL, заданного аргументом on_delete.Например, если у вас есть Nullable ForeignKey и вы хотите, чтобы он был установлен равным NULL при удалении ссылочного объекта:

user = models.ForeignKey(
    User,
    models.SET_NULL,
    blank=True,
    null=True,
)

on_delete не создает ограничение SQL в базе данных.Поддержка параметров каскада на уровне базы данных может быть реализована позже.

Возможные значения on_delete находятся в django.db.models:

CASCADE

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

Model.delete () не вызывается в связанных моделях, но сигналы pre_delete и post_delete отправляются для всех удаленныхobjects.

PROTECT

Предотвратить удаление ссылочного объекта, подняв ProtectedError, подкласс django.db.IntegrityError.

SET_NULL

Установить ForeignKeyноль;это возможно только в том случае, если null равно True.

SET_DEFAULT Установите ForeignKey в значение по умолчанию;значение по умолчанию для ForeignKey должно быть установлено.

SET ()

Установите для ForeignKey значение, переданное в SET (), или, если вызывается, вызывается результат его вызова.В большинстве случаев передача вызываемого будет необходима, чтобы избежать выполнения запросов во время импорта вашего models.py:

    from django.conf import settings
    from django.contrib.auth import get_user_model
    from django.db import models

    def get_sentinel_user():
        return get_user_model().objects.get_or_create(username='deleted')[0]

    class MyModel(models.Model):
        user = models.ForeignKey(
            settings.AUTH_USER_MODEL,
            on_delete=models.SET(get_sentinel_user),
        )

DO_NOTHING

Не предпринимать никаких действий.Если ваша база данных обеспечивает ссылочную целостность, это вызовет IntegrityError, если вы вручную не добавите ограничение SQL ON DELETE в поле базы данных.

...