fix(gerp): 对齐遗留库列名并清理 Asset 表 Flask 期遗留文件列
models.py:CompanyInfo 三个身份证列与 PersonalPage.QQ 补 db_column,匹配库中 *IdCard / Qq 实际列名;新增 0044 仅状态迁移(SeparateDatabaseAndState,零 DDL)记录该对齐。 新增 0045:条件删除 Asset 表 8 个 Flask 期文件资产列(FileName/FileSHA1/FileSize/MimeType/StoragePath/UploaderUUID/RefCount/CreateTime)。这些列 NOT NULL 且无默认值,导致新增企业资产必然报 1364;删除前先解除 UploaderUUID 上的遗留外键 asset_ibfk_1。按 information_schema 判定存在性,幂等可重入。
This commit is contained in:
1 parent
31b0ab885f
commit
b5a617d044
3 files changed
+126
-4
No files matched your search
@@ -0,0 +1,46 @@
|
||||
"""对齐遗留库列名:CompanyInfo 三个身份证列 + PersonalPage.QQ
|
||||
|
||||
背景:CompanyInfo / PersonalPage 为 Flask 时期建表,实际列名为 `LegalPersonIdCard` /
|
||||
`OperatorIdCard` / `FinanceManagerIdCard` / `Qq`(IdCard、Qq),而模型原先按
|
||||
`IDCard` / `QQ` 推导列名。MySQL 列名大小写不敏感,故线上读写无异常,但
|
||||
`manage.py gvsdsdk_check_schema` 会报 schema 漂移。
|
||||
|
||||
本迁移仅更新 Django 迁移状态以匹配模型新增的 db_column 声明,**不产生任何 DDL**:
|
||||
真实表列名已与模型 db_column 一致,无需重命名。
|
||||
"""
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('gerp', '0043_remove_userroleworkgroup_position'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.SeparateDatabaseAndState(
|
||||
state_operations=[
|
||||
migrations.AlterField(
|
||||
model_name='companyinfo',
|
||||
name='legalpersonidcard',
|
||||
field=models.CharField(db_column='LegalPersonIdCard', default='', max_length=32, verbose_name='法人身份证'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='companyinfo',
|
||||
name='operatoridcard',
|
||||
field=models.CharField(db_column='OperatorIdCard', default='', max_length=32, verbose_name='经办人身份证'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='companyinfo',
|
||||
name='financemanageridcard',
|
||||
field=models.CharField(db_column='FinanceManagerIdCard', default='', max_length=32, verbose_name='财务身份证'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='personalpage',
|
||||
name='qq',
|
||||
field=models.CharField(db_column='Qq', default='', max_length=256, verbose_name='QQ'),
|
||||
),
|
||||
],
|
||||
database_operations=[],
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,76 @@
|
||||
"""清理 Asset 表 Flask 时期遗留的 8 个文件资产列
|
||||
|
||||
背景:`Asset` 表最初由 Flask 时期作为文件资产表创建(FileName/FileSHA1/FileSize/
|
||||
MimeType/StoragePath/UploaderUUID/RefCount/CreateTime),后经 ALTER 追加了 9 个
|
||||
企业资产列。这 8 个文件列均为 NOT NULL 且无默认值,导致经 Django 新增企业资产时
|
||||
必然报错 1364(Field 'FileName' doesn't have a default value)。
|
||||
|
||||
文件资产已由 `FileAsset` 表承载,此处条件删除这 8 个遗留列:先解除这些列上的遗留
|
||||
外键(如 UploaderUUID → user.UserUUID),再逐列删除。按 information_schema 判定
|
||||
存在性,幂等,兼容已清理 / 全新建库 / 上次中断的环境。
|
||||
|
||||
反向迁移为尽力恢复:按原类型重加为可空列,不恢复 NOT NULL、唯一索引与外键。
|
||||
"""
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
LEGACY_COLUMNS = {
|
||||
'FileName': 'VARCHAR(256)',
|
||||
'FileSHA1': 'VARCHAR(40)',
|
||||
'FileSize': 'INT',
|
||||
'MimeType': 'VARCHAR(128)',
|
||||
'StoragePath': 'VARCHAR(512)',
|
||||
'UploaderUUID': 'BINARY(16)',
|
||||
'RefCount': 'INT',
|
||||
'CreateTime': 'DATETIME',
|
||||
}
|
||||
|
||||
|
||||
def _ExistingColumns(cursor, table):
|
||||
"""返回表当前实际存在的列名集合。"""
|
||||
cursor.execute(
|
||||
'SELECT COLUMN_NAME FROM information_schema.COLUMNS '
|
||||
'WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = %s',
|
||||
[table],
|
||||
)
|
||||
return {row[0] for row in cursor.fetchall()}
|
||||
|
||||
|
||||
def _DropLegacyColumns(apps, schema_editor):
|
||||
"""先解除遗留列上的外键,再按存在性逐列删除。"""
|
||||
connection = schema_editor.connection
|
||||
with connection.cursor() as cursor:
|
||||
existing = _ExistingColumns(cursor, 'Asset')
|
||||
cursor.execute(
|
||||
'SELECT CONSTRAINT_NAME, COLUMN_NAME FROM information_schema.KEY_COLUMN_USAGE '
|
||||
'WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = %s '
|
||||
'AND REFERENCED_TABLE_NAME IS NOT NULL',
|
||||
['Asset'],
|
||||
)
|
||||
for constraint, column in cursor.fetchall():
|
||||
if column in LEGACY_COLUMNS and column in existing:
|
||||
cursor.execute(f'ALTER TABLE `Asset` DROP FOREIGN KEY `{constraint}`')
|
||||
for column in LEGACY_COLUMNS:
|
||||
if column in existing:
|
||||
cursor.execute(f'ALTER TABLE `Asset` DROP COLUMN `{column}`')
|
||||
|
||||
|
||||
def _RestoreLegacyColumns(apps, schema_editor):
|
||||
"""反向:按原类型重加为可空列(尽力恢复)。"""
|
||||
connection = schema_editor.connection
|
||||
with connection.cursor() as cursor:
|
||||
existing = _ExistingColumns(cursor, 'Asset')
|
||||
for column, column_type in LEGACY_COLUMNS.items():
|
||||
if column not in existing:
|
||||
cursor.execute(f'ALTER TABLE `Asset` ADD COLUMN `{column}` {column_type} NULL')
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('gerp', '0044_align_legacy_column_names'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(_DropLegacyColumns, _RestoreLegacyColumns),
|
||||
]
|
||||
@@ -99,7 +99,7 @@ class CompanyInfo(QModel):
|
||||
SocialSecurityBank = models.CharField(max_length=128, default='', verbose_name='社保银行')
|
||||
SocialSecurityAccount = models.CharField(max_length=64, default='', verbose_name='社保账号')
|
||||
LegalPersonName = models.CharField(max_length=64, default='', verbose_name='法人姓名')
|
||||
LegalPersonIDCard = models.CharField(max_length=32, default='', verbose_name='法人身份证')
|
||||
LegalPersonIDCard = models.CharField(max_length=32, default='', db_column='LegalPersonIdCard', verbose_name='法人身份证')
|
||||
LegalPersonGender = models.CharField(max_length=16, default='', verbose_name='法人性别')
|
||||
LegalPersonBirthday = models.CharField(max_length=32, default='', verbose_name='法人生日')
|
||||
LegalPersonNationality = models.CharField(max_length=32, default='', verbose_name='法人国籍')
|
||||
@@ -111,7 +111,7 @@ class CompanyInfo(QModel):
|
||||
LegalPersonShareRatio = models.CharField(max_length=16, default='', verbose_name='法人持股比例')
|
||||
LegalPersonAppointment = models.CharField(max_length=32, default='', verbose_name='法人任职')
|
||||
OperatorName = models.CharField(max_length=64, default='', verbose_name='经办人姓名')
|
||||
OperatorIDCard = models.CharField(max_length=32, default='', verbose_name='经办人身份证')
|
||||
OperatorIDCard = models.CharField(max_length=32, default='', db_column='OperatorIdCard', verbose_name='经办人身份证')
|
||||
OperatorPhone = models.CharField(max_length=32, default='', verbose_name='经办人电话')
|
||||
OperatorEmail = models.CharField(max_length=128, default='', verbose_name='经办人邮箱')
|
||||
OperatorDepartment = models.CharField(max_length=128, default='', verbose_name='经办人部门')
|
||||
@@ -119,7 +119,7 @@ class CompanyInfo(QModel):
|
||||
FinanceManagerName = models.CharField(max_length=64, default='', verbose_name='财务负责人')
|
||||
FinanceManagerPhone = models.CharField(max_length=32, default='', verbose_name='财务电话')
|
||||
FinanceManagerEmail = models.CharField(max_length=128, default='', verbose_name='财务邮箱')
|
||||
FinanceManagerIDCard = models.CharField(max_length=32, default='', verbose_name='财务身份证')
|
||||
FinanceManagerIDCard = models.CharField(max_length=32, default='', db_column='FinanceManagerIdCard', verbose_name='财务身份证')
|
||||
Remark = models.TextField(default='', verbose_name='备注')
|
||||
ReviewStatus = models.SmallIntegerField(default=0, verbose_name='审核状态')
|
||||
ReviewRemark = models.CharField(max_length=512, default='', verbose_name='审核备注')
|
||||
@@ -980,7 +980,7 @@ class PersonalPage(QModel):
|
||||
Classification = models.CharField(max_length=256, default='', verbose_name='分类')
|
||||
Github = models.CharField(max_length=256, default='', verbose_name='GitHub')
|
||||
Wechat = models.CharField(max_length=256, default='', verbose_name='微信')
|
||||
QQ = models.CharField(max_length=256, default='', verbose_name='QQ')
|
||||
QQ = models.CharField(max_length=256, default='', db_column='Qq', verbose_name='QQ')
|
||||
SelfIntroduction = models.TextField(default='', verbose_name='自我介绍')
|
||||
ProjectExperience = models.CharField(max_length=256, default='', verbose_name='项目经验')
|
||||
SatisfiedCustomers = models.CharField(max_length=256, default='', verbose_name='满意客户')
|
||||
|
||||
Reference in new issue
Block a user