Django - 如何防止数据库外键约束的创建

11

我有一个以数据库视图为后端支持的模型。

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选项,让syncdb创建OrgCode表,然后在syncdb之后再把Meta:db_table加回去。

是否有一种方法可以防止为某些模型或字段创建外键约束?

更新:我向相关模型添加了一个静态方法,指示它是一个视图

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

然后在django_mssql的creation.py中重写了DatabaseCreation.sql_for_inline_foreign_key_references:

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)    

从syncdb生成的SQL语句中省略了约束条件:

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信号...

2个回答

21

Django开发版本为ForeignKey模型字段添加了db_constraint字段 - 文档


谢谢!那正是我需要的,现在我只需要等它在发布中出现,然后就可以移除我的 hack 了。 - Joe Petrini
1
db_constraint 自 1.6 版本以来已经可以安全使用。 - Ivor Zhou
我已经为Postgres完成了这个操作,并在迁移文件中获得了一个更改字段的条目,但是Postgres中的数据库模式根本没有发生变化。 - Tim Richardson
@TimRichardson,我认为在你的情况下,DB模式不需要更改,因为Django在DB级别上实现其约束。相反,尝试在Postgres中搜索有趣的约束条件,例如在这里描述的方式:https://dba.stackexchange.com/questions/214863/how-to-list-all-constraints-of-a-table-in-postgresql - iurii

4
如果在模型的Meta类中设置managed=False(Django文档),当您运行syncdb时,Django将不会创建表。
class AssessmentLocation(models.Model):
    name = models.CharField(max_length=150)
    org  = models.ForeignKey(OrgCode)

    class Meta:
        managed = False

Django有一个钩子可以提供初始的SQL数据。我们可以(滥用?)这个钩子来让Django在运行syncdb后立即创建表。
创建一个文件myapp/sql/assessmentlocation.sql,其中包含创建表语句:
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 创建表可能会出现问题。否则,我认为这种方法是可行的。

谢谢!我研究了一下,它确实有效。视图相关的对象模型是我正在构建的框架的一部分,将由其他开发人员使用。我尽量不偏离syncdb模型创建和标准的Django文档。 - Joe Petrini

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接