TGStat
TGStat
Введите текст для поиска
Расширенный поиск каналов
  • flag Russian
    Язык сайта
    flag Russian flag English flag Uzbek
  • Вход на сайт
  • Каталог
    Каталог каналов и чатов Региональные подборки Тематические подборки Платные каналы Поиск каналов
    Добавить канал/чат
  • Рейтинги
    Рейтинг каналов Рейтинг чатов Рейтинг публикаций
    Рейтинги брендов и персон
  • Аналитика
  • Поиск по публикациям
  • Мониторинг Telegram
  • Продвижение
    Реклама через Яндекс Бизнес Реклама в каналах через TGStat Agency Реклама на сайте TGStat.ru
Павлин Шарит

23 Feb, 11:04

Открыть в Telegram Поделиться Пожаловаться

Опасность использования loaddata в миграциях

Есть одна команда в Django, которая работает идеально - ровно до того момента, пока ты не попробуешь накатить миграции с нуля

Речь о call_command("loaddata", ...) внутри миграции

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

Почему?

Когда ты пишешь RunPython и вызываешь apps.get_model() - ты получаешь историческую модель. Это не та модель, что у тебя сейчас в models.py, а её слепок на момент конкретной миграции. Django специально реконструирует её из цепочки миграций, чтобы INSERT и UPDATE содержали только те колонки, которые реально существуют в базе прямо сейчас - в процессе накатки

А вот loaddata на эту логику плевать хотел - он всегда импортирует модель напрямую из приложения, то есть берёт текущее состояние models.py со всеми полями, которые ты добавил позже. В итоге команда пытается сделать INSERT с колонкой, которой в базе ещё нет

Решение - отказаться от loaddata в пользу RunPython

Читаем JSON сами, создаём объекты через историческую модель из apps.get_model(). Тогда Django собирает INSERT только по полям, которые реально существуют на момент этой миграции - и никакие будущие изменения схемы её не сломают

def load_fixture(apps, schema_editor):
MyModel = apps.get_model("myapp", "MyModel")
MyModel.objects.all().delete()

fixture_path = (
Path(__file__).resolve().parent.parent
/ "fixtures"
/ "my_fixture.json"
)
with fixture_path.open("r", encoding="utf-8") as f:
data = json.load(f)

objs = [
MyModel(**item["fields"], pk=item.get("pk"))
for item in data
if item.get("model") == "myapp.mymodel"
]
MyModel.objects.bulk_create(objs)

Простое правило - миграции должны быть детерминированными и самодостаточными, без привязки к текущему состоянию моделей

Поддержать на Boosty
Посмотреть на Youtube
Николай Павлин - Разбираю технологии работающие в реальных проектах
Привет! Я Николай Павлин — руководитель департамента ИТ в компании которая создает hardware-продукты для мониторинга здоровья. Прошел путь от разработчика до руководителя команд разработки (15+ человек). Помог компании получить грант ФСИ (и смог получить поддержку уже на свой личный проект), стать ...

2k 0 4 3 23
Каталог
Каталог каналов и чатов Подборки каналов Поиск каналов Добавить канал/чат
Рейтинги
Рейтинг каналов Telegram Рейтинг чатов Telegram Рейтинг публикаций Рейтинги брендов и персон
API
API статистики API поиска публикаций API Callback
Наши каналы
@TGStat @TGStat_Chat @telepulse @TGStatAPI
Почитать
Академия TGStat Исследование Telegram 2019 Исследование Telegram 2021 Исследование Telegram 2023
Контакты
Справочный центр Поддержка Почта Вакансии
Всякая всячина
Пользовательское соглашение Политика конфиденциальности Публичная оферта
Наши боты
@TGStat_Bot @SearcheeBot @TGAlertsBot @tg_analytics_bot @TGStatChatBot