Django — Как предотвратить создание ограничения внешнего ключа базы данных

#django #django-models #django-mssql

#django #django-модели #django-mssql

Вопрос:

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

 class OrgCode(models.Model):
    org_code                = models.CharField(db_column=u'code',max_length=15) 
    org_description         = models.CharField(max_length=250)
    org_level_num           = models.IntegerField()

    class Meta:
        db_table = u'view_FSS_ORG_PROFILE'
  

Мне нужно сослаться на это в другой модели

 class AssessmentLocation(models.Model):
    name                = models.CharField(max_length=150)
    org                 = models.ForeignKey(OrgCode)
  

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

  u"Foreign key 'FK__main_asse__org__1D114BD1' 
 references object 'view_FSS_ORG_PROFILE' 
 which is not a user table.", None, 0, -214
7217900), None)
Command:
CREATE TABLE [main_assessmentlocation] (
    [id] int IDENTITY (1, 1) NOT NULL PRIMARY KEY,
    [name] nvarchar(150) NOT NULL,
    [org] int NOT NULL REFERENCES [view_FSS_ORG_PROFILE] ([id]),
)
  

Обходной путь состоит в том, чтобы удалить Meta: db_table, указывающий на представление, и позволить sync db создать таблицу OrgCode, затем поместить Meta: db_table обратно после syncdb.

Есть ли способ предотвратить создание ограничений внешнего ключа для определенных моделей или полей?

Обновление: я добавил статический метод к связанной модели, указывающий, что это представление

 class OrgCode(models.Model):
    org_code                = models.CharField(max_length=15)
    org_description         = models.CharField(max_length=250)

    @staticmethod
    def is_backend_view():
        return True
  

Затем переопределите DatabaseCreation.sql_for_inline_foreign_key_references в django_mssql creation.py:

 def sql_for_inline_foreign_key_references(self, field, known_models, style):
    try: 
        field.rel.to.is_backend_view()
        return "", False
    except:
        return super(DatabaseCreation,self).sql_for_inline_foreign_key_references(field, known_models, style)    
  

Сгенерированный sql из syncdb не учитывает ограничение:

 CREATE TABLE [main_assessmentlocation] (
    [id] int IDENTITY (1, 1) NOT NULL PRIMARY KEY,
    [name] nvarchar(150) NOT NULL,
    [org] int, -- NO FK CONSTRAINT ANYMORE --
);
  

Это действительно связано со взломом django_mssql, поэтому я собираюсь продолжать попытки, возможно, подключение к сигналу django.db.backends.signals.connection_created сработает…

Ответ №1:

в версии разработки django есть db_constraint поле для ForeignKey поля модели — docs.

Комментарии:

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

2. db_constraint может безопасно использоваться с версии 1.6

3. Я сделал это для postgres и получаю запись alter field в файле миграции, но схема базы данных в postgres вообще не меняется.

4. @TimRichardson, я не думаю, что в вашем случае схему БД нужно менять, поскольку Django реализует свои ограничения на уровне БД. Вместо этого попробуйте поискать интересное ограничение в Postgres, например, как описано здесь: dba.stackexchange.com/questions/214863 /…

Ответ №2:

Если вы установите managed=False (Django docs) в Meta классе вашей модели, Django не создаст таблицу при запуске syncdb.

 class AssessmentLocation(models.Model):
    name = models.CharField(max_length=150)
    org  = models.ForeignKey(OrgCode)

    class Meta:
        managed = False
  

В Django есть перехват для предоставления исходных данных sql. Мы можем (ab?) использовать это, чтобы заставить Django создать таблицу сразу после запуска syncdb.

Создайте файл myapp/sql/assessmentlocation.sql , содержащий инструкцию create table:

 CREATE TABLE [main_assessmentlocation] (
    [id] int IDENTITY (1, 1) NOT NULL PRIMARY KEY,
    [name] nvarchar(150) NOT NULL,
    [org] int, -- NO FK CONSTRAINT ANYMORE --
);
  

Если у вас есть другие модели с внешними ключами к AssessmentLocation модели, у вас могут возникнуть проблемы, если Django попытается применить ограничение внешнего ключа перед выполнением пользовательского sql для создания таблицы. В противном случае, я думаю, этот подход сработает.

Комментарии:

1. Спасибо! Я изучил это, и это действительно работает. Объектная модель, основанная на представлении, является частью фреймворка, который я создаю для использования другими разработчиками. Я пытаюсь не отклоняться от создания модели syncdb и стандартных документов django.