Проблемы с типами содержимого при загрузке фикстуры в Django

104

У меня проблемы с загрузкой фикстур Django в мою базу данных MySQL из-за конфликтов типов содержимого. Сначала я попытался сбросить данные только из моего приложения следующим образом:

./manage.py dumpdata escola > fixture.json

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

./manage.py dumpdata contenttypes auth escola > fixture.json

Теперь проблема заключается в следующем нарушении ограничения, когда я пытаюсь загрузить данные как тестовое приспособление:

IntegrityError: (1062, "Duplicate entry 'escola-t23aluno' for key 2")

Кажется, проблема в том, что Django пытается динамически воссоздать типы контента с разными значениями первичного ключа, которые конфликтуют со значениями первичного ключа из фикстуры. Это похоже на ошибку, описанную здесь: http://code.djangoproject.com/ticket/7052

Проблема в том, что рекомендуемый обходной путь - сбросить приложение contenttypes, которое я уже делаю !? Что дает? Если это имеет значение, у меня есть некоторые разрешения для пользовательской модели, как описано здесь: http://docs.djangoproject.com/en/dev/ref/models/options/#permissions

Гердемб
источник

Ответы:

149

manage.py dumpdata --naturalбудет использовать более надежное представление внешних ключей. В django они называются «естественными ключами». Например:

  • Permission.codename используется в пользу Permission.id
  • User.username используется в пользу User.id

Подробнее: раздел естественных ключей в "сериализации объектов django"

Еще несколько полезных аргументов в пользу dumpdata:

  • --indent=4 сделать его читабельным.
  • -e sessions исключить данные сеанса
  • -e admin исключить историю действий админа на админке
  • -e contenttypes -e auth.Permissionисключить объекты, которые автоматически воссоздаются из схемы каждый раз во время syncdb. Используйте его только вместе, --naturalиначе вы можете получить плохо выровненные идентификационные номера.
Лыжи
источник
1
@skyjur Почему всегда использовать -e contenttypes -e auth.permissionс --natural? Я просто попробовал без --naturalопции, и это сработало. Также в документации здесь говорится, что следует использовать эту опцию, если DUMPING auth.permission и contenttypes.
wlnirvana
6
@winirvana, потому что после того, как вы начнете с нуля и выполните syncdb, вновь созданные ContentTypeи Permissionне гарантируют получение того же идентификатора, что и раньше. Ваш дамп данных содержит идентификаторы, которые могут ссылаться на разные объекты в другой базе данных, куда вы загружаете данные. Это могло сработать для вас по одной из следующих причин: 1) ваши данные не имели ссылок на эти объекты 2) исходные идентификаторы Permission / ContentTypes были сохранены 3) ваши loaddata были успешными, но у вас действительно есть поврежденные данные из-за объектов относится к неправильным объектам, а вы еще об этом не знаете
Лыжные
12
Флаг --naturalтеперь устарел в пользу --natural-foreign--natural-primary)
frnhr
16
Окончательная команда может быть такой:manage.py dumpdata --natural-foreign --natural-primary -e contenttypes -e auth.Permission --indent 4 > project_dump.json
Паоло
4
--naturalтеперь полностью удален, а не просто устарел. Используйте --natural-foreignили --natural-primaryвместо.
Code-Apprentice
35

Да, это действительно раздражает. Некоторое время я работал над этим, выполняя «сброс manage.py» в приложении contenttypes перед загрузкой фикстуры (чтобы избавиться от автоматически сгенерированных данных contenttypes, которые отличались от дампированной версии). Это сработало, но в конце концов мне надоели хлопоты и полностью отказаться от приспособлений в пользу прямых SQL-дампов (конечно, тогда вы теряете переносимость БД).

update - лучший ответ - использовать --naturalфлаг dumpdata, как указано в ответе ниже. Когда я писал этот ответ, этого флага еще не было.

Карл Мейер
источник
3
Я тоже столкнулся с этим, сброс приложения contenttypes тоже помог мне. Спасибо за чаевые!
Beau
Как ты их сбросил? В классе тестового случая? Приведите пример, пожалуйста
Олег Тарасенко
4
Я не использую фикстуры для модульных тестов, я обычно создаю тестовые данные, используя ORM в методе setup (), потому что легче синхронизировать с тестами. Так что мне никогда не приходилось делать это в классе TestCase, хотя я уверен, что если вы покопаетесь в коде класса TestCase Django, вы сможете выяснить, как сделать сброс после syncdb и до загрузки фикстуры в подклассе. Для меня это было просто «./manage.py reset contenttypes» в сценарии bash до «./manage.py loaddata my_fixture».
Карл Мейер,
32

Попробуйте пропустить типы содержимого при создании фикстуры:

./manage.py dumpdata --exclude contenttypes > fixture.json

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

Евгений
источник
32

Ответы здесь все старые ... По состоянию на 2017 год лучший ответ:

manage.py dumpdata --natural-foreign --natural-primary -e contenttypes -e auth.Permission --indent 4
Привет мир
источник
11

Я не использовал MySQL, а вместо этого импортировал некоторые данные с живого сервера в sqlite. Очистка contenttypesданных приложения перед выполнением loaddataсработала:

from django.contrib.contenttypes.models import ContentType
ContentType.objects.all().delete()
quit()

А потом

python manage.py loaddata data.json
MadeOfAir
источник
django.core.exceptions.ImproperlyConfigured: запрошен параметр INSTALLED_APPS, но параметры не настроены. Вы должны либо определить переменную среды DJANGO_SETTINGS_MODULE, либо вызвать settings.configure () перед доступом к настройкам.
Барни
Вероятно, лучше всего это будет работать в рамках специальной команды управления.
Барни
10

Я решил эту проблему в своих тестовых примерах, сбросив приложение contenttypes из модульного теста перед загрузкой файла дампа. Карл предложил это уже с помощью manage.pyкоманды, и я делаю то же самое, только используя call_commandметод:

>>> from django.core import management
>>> management.call_command("flush", verbosity=0, interactive=False)
>>> management.call_command("reset", "contenttypes", verbosity=0, interactive=False)
>>> management.call_command("loaddata", "full_test_data.json", verbosity=0)

Мой full_test_data.jsonприбор содержит дамп приложения contenttypes, который соответствует остальным тестовым данным. Сброс приложения перед загрузкой предотвращает дублирование ключа IntegrityError.

Джесси Л
источник
7
python manage.py dumpdata --natural-primary --exclude=contenttypes --exclude=auth.Permission --exclude=admin.logentry --exclude=sessions.session --indent 4 > initial_data.json

У меня это работает. Здесь я исключаю все, что касается настоящих моделей.

  • Если вы видите любую другую модель, кроме созданных вами моделей, вы можете безопасно исключить их. Одним из недостатков этого подхода является потеря данных журнала, а также данных аутентификации.
Оджас Кале
источник
6

Вам нужно использовать естественные ключи для представления любого внешнего ключа и отношений «многие ко многим». Более того, было бы неплохо исключить sessionтаблицу в sessionsприложении и logentryтаблицу в adminприложении.

Django 1.7+

python manage.py dumpdata --natural-foreign --exclude contenttypes --exclude auth.permission --exclude admin.logentry --exclude sessions.session --indent 4 > fixture.json

Джанго <1,7

python manage.py dumpdata --natural --exclude contenttypes --exclude auth.permission --exclude admin.logentry --exclude sessions.session --indent 4 > fixture.json

Согласно документации Django , --naturalон устарел в версии 1.7, поэтому --natural-foreignследует использовать эту опцию .

Вы также можете опустить первичный ключ в сериализованных данных этого объекта, поскольку он может быть вычислен во время десериализации путем передачи --natural-primaryфлага.

python manage.py dumpdata --natural-foreign --natural-primary --exclude contenttypes --exclude auth.permission --exclude admin.logentry --exclude sessions.session --indent 4 > fixture.json
lmiguelvargasf
источник
2
./manage.py dumpdata app.Model --natural-foreign

изменится

  "content_type": 123

к

  "content_type": [
    "app_label",
    "model"
  ],

И приспособление работает прямо TestCaseсейчас

Даниил Машкин
источник
2

Django 2.2.5

python manage.py dumpdata --exclude=contenttypes > datadump.json

это помогло мне

Игорь З
источник
Это вызовет проблему при загрузке данных, возможно, несовпадение с типом содержимого в новой базе данных
Ян Чжоу
1

Я дам еще один возможный ответ, который я только что понял. Может быть, это поможет ОП, может, кому-то еще.

У меня есть таблица отношений "многие ко многим". У него есть первичный ключ и два внешних ключа к другим таблицам. Я обнаружил, что если у меня есть запись в приспособлении, у которой два внешних ключа совпадают с другой записью, уже находящейся в таблице с другим pk, она завершится ошибкой. Таблицы отношений M2M имеют «уникальные вместе» для двух внешних ключей.

Итак, если это отношения M2M, которые нарушаются, посмотрите на добавляемые внешние ключи, посмотрите на свою базу данных, чтобы увидеть, не указана ли уже эта пара FK под другим PK.

орбливион
источник
1

Это очень, очень раздражает ... Меня это каждый раз кусает.

Я пытался сбросить данные с помощью --exclude contenttypes и --natural, у меня всегда возникают проблемы ..

Для меня лучше всего просто выполнить a truncate table django_content_type;после syncdb и ЗАТЕМ загрузить данные.

Конечно, для автозагрузки initial_data.json вы ошибаетесь.

h3.
источник
Для меня усечение таблицы до loaddata вызывает разные ошибки. Не повезло с этой техникой.
shacker
1

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

$ python manage.py makemigrations
$ python manage.py migrate
$ python manage.py loaddata fixtures/initial_data.json

И это сработало как шарм

Джеймс Уондери
источник
0

В моем случае я сбросил данные из auth( ./manage.py dumpddata auth > fixtures/auth.json), чтобы использовать приспособление для тестирования.

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

Мое решение снова регенерировало приспособление auth.json. Здесь было удалено множество записей, auth.permissionсвязанных со старыми моделями, которые у меня были.

Пабло Кастеллано
источник
0

Я перепробовал все способы, указанные выше, у меня ничего не сработало. Я должен исключить полную модель аутентификации и отлично работает.

python manage.py dumpdata --natural-primary --exclude=contenttypes --exclude=auth --exclude=admin.logentry --exclude=sessions.session --indent 4 > live.json
Чандра Шекхар Панди
источник