Миграция Django с нуля не удалась: 'no such table', после добавления приемников сигналов

Я добавил в свой код несколько приемников сигналов, и все работало нормально, пока я не переместил его в систему контроля версий, и конвейер CI/CD не сработал. При попытке миграции он выдавал сообщение:

django.db.utils.OperationalError: no such table: badges_badge

Но миграции работали на моей машине!

Однако CI/CD начинается с нуля, поэтому я попробовал удалить мои db.sqlite3 локально, затем попытался повторно мигрировать с python manage.py migrate:

 django.db.utils.OperationalError: no such table: badges_badge

Так что миграция из существующей базы данных работает, но не из новой.

Мой signals.py:

from django.conf import settings
from django.db.models.signals import post_save
from django.dispatch import receiver

from badges.badge_stuff import badges


@receiver(post_save)
def update_badges(sender, **kwargs):
    for badge in badges:
        badge.update()

Мой apps.py:

from django.apps import AppConfig


class BadgesConfig(AppConfig):
    name = 'badges'

    def ready(self):
        # Register signal listeners.
        from . import signals

Почему это работает с существующей базой данных, но не работает при ее инициализации? Как это исправить?

У меня была такая проблема, и она была связана с тем, как я регистрировал свои сигналы.

Проблема в том, что код в apps.ready() запускается до любых миграций, поэтому если signals.py зависит от моделей, которые еще не существуют в базе данных (например, при миграции с нуля), это приведет к ошибке. Это может произойти, когда ваш signals.py импортирует другие модули, которые затем зависят от ваших моделей.

Здесь badges.badge_stuff.badges импортирует модель Badge, которая создается при первой миграции. Поэтому он не может найти ее.

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

Модифицируйте вышеуказанное следующим образом:

from django.apps import AppConfig
from django.core.signals import pre_save, post_migrate


class BadgesConfig(AppConfig):
    name = 'badges'

    def register_signals(self, **kwargs):
        # If your signals are decorated with @receiver, the line below is all you need
        from . import signals
        # Otherwise, explicitly connect the signal handler
        pre_save.connect(signals.my_callback)

    def ready(self):
        post_migrate.connect(self.register_signals, sender=self)

И, надеюсь, теперь ваши миграции будут работать!

Не забудьте зарегистрировать ваше приложение в INSTALLED_APPS, используя этот новый AppConfig в settings.py:

INSTALLED_APPS = [
    ...
    'badges.apps.BadgesConfig',
    # Or just 'badges' for Django 4.0+
    ...
]
Вернуться на верх