Django создает миграцию, которая, похоже, уже отражена в исходной схеме postgresql

Я изменил внешний ключ calendar как nullable в моей Django модели CalendarAssign. \

# ---------------------------------------------------------------------------- #
class Calendars(models.Model):
  id = models.CharField(primary_key=True, max_length=100)
  cms_id = models.CharField(max_length=100)
  default_program = models.ForeignKey(ControlPrograms, models.CASCADE, blank=True, null=True)
  timestamp = models.DateTimeField(auto_now_add=True)

  class Meta:
    managed = True
    db_table = 'calendars'

# ---------------------------------------------------------------------------- #
class CalendarAssign(models.Model):
  device_mac = models.ForeignKey(Device, models.CASCADE)
  calendar = models.ForeignKey(Calendars, models.CASCADE, null=True)
  timestamp = models.DateTimeField(auto_now_add=True)

  class Meta:
    managed = True
    db_table = 'calendar_assign'

При применении миграции, созданной Django, возникает ошибка.

    operations = [
        migrations.AlterField(
            model_name='calendarassign',
            name='calendar',
            field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='smartbridge.Calendars'),
        )

Генерируемый sql-код использует неподдерживаемую функцию 'WITH ORDINALITY'. Это происходит потому, что Django не поддерживает версию Postrges, которую мы используем.
WITH ORDINALITY появляется в psql 9.4, но мы используем версию 9.1.
И Postgres, и Django не могут быть обновлены прямо сейчас. Поэтому мне нужно написать миграцию вручную (без функции 'WITH ORDINALITY').

        migrations.RunSQL("DO $$DECLARE r record;\
                            BEGIN\
                                FOR r IN SELECT table_name,constraint_name \
                                    FROM information_schema.constraint_table_usage \
                                    WHERE table_name IN ('calendars') AND constraint_name like '%calendar_assign_calendar_id%'\
                                LOOP\
                                    EXECUTE 'ALTER TABLE calendar_assign DROP CONSTRAINT '|| quote_ident(r.constraint_name) || ';';\
                                END LOOP;\
                            ALTER TABLE calendar_assign ALTER COLUMN calendar_id DROP NOT NULL; \
                            ALTER TABLE calendar_assign \
                            ADD CONSTRAINT calendar_assign_calendar_id_fk_calendars_id FOREIGN KEY (calendar_id) REFERENCES calendars(id);\
                            END$$;")

Миграция, похоже, работает нормально. calendar теперь nullable, но Django все еще обнаруживает некоторые различия.
Если попросить Django сгенерировать миграцию, соответствующую этой разнице, он сгенерирует то же самое, что и до моей ручной миграции.

Я бы хотел, чтобы Django не видел никакой разницы после моей миграции.

Спасибо

Думаю, вам придется установить managed = False на время, иначе команда makemigrations будет каждый раз думать, что ее еще не сделали обнуляемой.

Команда построения миграции обращается к предыдущим файлам миграции и таким образом строит концептуальную модель того, как будет выглядеть таблица в базе данных, если все предыдущие миграции состоялись. На основе этой модели она будет искать различия с вашей моделью Django, которую вы построили, и таким образом создаст для нее файл миграции.

Пока вы не выполните миграцию с помощью команды AlterField, Django будет думать, что вы не сделали поле nullable. Он не умеет разбирать SQL, поэтому даже если вы сделали его nullable там, он все равно будет считать, что поле является non-NULLable.

Установив значение managed=False [Django-doc], Django больше не будет управлять миграциями этого файла. Вы можете создать пустую миграцию [Django-doc] с помощью:

python3 manage.py makemigrations --empty

и используйте это для определения SQL-запросов, которые будут выполняться над таблицей.

Вернуться на верх