Django MSSQL:覆盖外键约束名称生成

如何解决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 类中的 DatabaseSchemaEditorsql_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 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-