如何解决Django MSSQL:覆盖外键约束名称生成
我正在尝试使用 django-mssql-backend 在 Django 3.0 中创建一个数据库模型,作为 SQL Server 2019 的 db 后端。该数据库对其中包含的表使用多个架构,其中一些表是非托管的(已经存在),而其他的则是通过迁移从头开始创建的。为了使多个模式工作,我使用了我在此处的另一个答案中找到的一个技巧,建议按如下方式格式化表名:
class MyModel(models.Model):
...
class Meta:
db_table = 'schema].[table'
这是为了使 SQL 编译为具有在外部自动形成的包装方括号完成模式/表定义。这样做的问题是 ForeignKey 对象使用这个表名生成了它们的约束名称,这会导致无效的约束名称出现,一旦表创建完成,就会导致迁移失败,并且是时候创建约束了。\>
它们是这样生成的:[schema1].[table1_colname_id_bc165567_fk2_schema2].[table_colname]
有没有办法覆盖这种行为?如果这可以通过分叉后端并添加手动编译代码来覆盖,我将如何去做?否则,如何在使用多个模式并充分利用 Django 附带的 ORM/迁移的同时在我的模型中使用外键?
解决方法
我终于弄明白了。在 fork django-mssql-backend 之后,我覆盖了 _create_index_name
模块中 _fk_constraint_name
类中的 DatabaseSchemaEditor
和 sql_server.pyodbc.schema
方法,将表名更改为 split('[')[-1]
,它省略了字符串的架构 hack 部分和额外的开放括号,但不应干扰没有应用该 hack 的表。
这里是重写的方法
(大部分代码与 django.db.backends.base.schema 中的原始实现相同):
def _create_index_name(self,table_name,column_names,suffix=""):
"""
Generate a unique name for an index/unique constraint.
The name is divided into 3 parts: the table name,the column names,and a unique digest and suffix.
"""
# CHANGE HERE (table_name to table_name.split('[')[-1]
_,table_name = split_identifier(table_name.split('[')[-1])
hash_suffix_part = '%s%s' % (names_digest(table_name,*column_names,length=8),suffix)
max_length = self.connection.ops.max_name_length() or 200
# If everything fits into max_length,use that name.
index_name = '%s_%s_%s' % (table_name,'_'.join(column_names),hash_suffix_part)
if len(index_name) <= max_length:
return index_name
# Shorten a long suffix.
if len(hash_suffix_part) > max_length / 3:
hash_suffix_part = hash_suffix_part[:max_length // 3]
other_length = (max_length - len(hash_suffix_part)) // 2 - 1
index_name = '%s_%s_%s' % (
table_name[:other_length],'_'.join(column_names)[:other_length],hash_suffix_part,)
# Prepend D if needed to prevent the name from starting with an
# underscore or a number (not permitted on Oracle).
if index_name[0] == "_" or index_name[0].isdigit():
index_name = "D%s" % index_name[:-1]
return index_name
def _fk_constraint_name(self,model,field,suffix):
def create_fk_name(*args,**kwargs):
return self.quote_name(self._create_index_name(*args,**kwargs))
return ForeignKeyName(
model._meta.db_table.split('[')[-1],[field.column],# CHANGE HERE (db_table to db_table.split('[')[-1]
split_identifier(field.target_field.model._meta.db_table.split('[')[-1])[1],[field.target_field.column],suffix,create_fk_name,)
如果 Django 的未来版本继续不支持多个模式,希望这对将来遇到类似问题的其他人有用。
编辑:我在 django-mssql-backend 存储库上创建了一个拉取请求来合并这些更改,所以如果这个问题的上下文得到批准,将来人们可能不会遇到这个问题。>
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。