python - 尝试在 mysql 数据库中设置枚举数据类型时出现问题
问题描述
我想做什么?
Django 不支持在 mysql 数据库中设置枚举数据类型。使用下面的代码,我尝试设置枚举数据类型。
错误详情
_mysql.connection.query(self, query) django.db.utils.ProgrammingError: (1064, "您的 SQL 语法有错误;请查看与您的 MariaDB 服务器版本相对应的手册,以了解在 'NOT 附近使用的正确语法NULL,
created_at
datetime(6) NOT NULL,user_id
bigint NOT NULL)' 在第 1 行")
我错过了什么吗?
具有所有选项的枚举类
class enumTokenTypes(models.TextChoices):
Registration = "Registration"
ForgotPassword = "Forgot Password"
模型中的用户令牌类
class tblusertokens(models.Model):
token_id = AutoField(primary_key=True)
token_type = EnumField(max_length=20, choices=enumTokenTypes.choices)
created_at = DateTimeField(auto_now_add=True, blank=True)
user = ForeignKey(tblusers, on_delete = models.CASCADE)
用户令牌在迁移中创建模型
class EnumField(CharField):
def db_type(self, connection):
return "enum"
migrations.CreateModel(
name='tblusertokens',
fields=[
('token_id', models.AutoField(primary_key=True, serialize=False)),
('token_type', clientauth.models.EnumField(choices=[('Registration', 'Registration'), ('Forgot Password', 'Forgotpassword')], max_length=20)),
('created_at', models.DateTimeField(auto_now_add=True)),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='clientauth.tblusers')),
],
)
赏金问题
为函数设置 2 个参数以传递逗号分隔值和默认值。
解决方案
数据类型应该enum('Registration', 'Forgot Password')
不仅仅是enum
.
class EnumField(CharField):
def db_type(self, connection):
if connection.vendor == 'mysql':
return 'enum({0})'.format(','.join("'%s'" % value for value, label in self.choices))
return super().db_type(connection)
参考:https ://dev.mysql.com/doc/refman/8.0/en/enum.html
数据库默认
虽然上面的 MySQL 8.0 文档中没有明确提到,但您也可以指定数据库默认值。
class EnumField(CharField):
def __init__(self, *args, **kwargs):
self.db_default = kwargs.pop('db_default', None)
super().__init__(*args, **kwargs)
def db_type(self, connection):
if connection.vendor == 'mysql':
if self.db_default is not None:
return "enum({0}) DEFAULT '{1}'".format(','.join("'%s'" % value for value, label in self.choices), self.db_default)
return 'enum({0})'.format(','.join("'%s'" % value for value, label in self.choices))
return super().db_type(connection)
def deconstruct(self):
name, path, args, kwargs = super().deconstruct()
if self.db_default:
kwargs['db_default'] = self.db_default
return name, path, args, kwargs
用法:
token_type = EnumField(max_length=20, choices=enumTokenTypes.choices, db_default=enumTokenTypes.ForgotPassword)
关于deconstruct()
方法
来自https://docs.djangoproject.com/en/3.2/howto/custom-model-fields/#field-deconstruction:
编写方法的对应点
__init__()
是编写deconstruct()
方法。它在模型迁移期间用于告诉 Django 如何获取新字段的实例并将其简化为序列化形式 - 特别是传递__init__()
给重新创建它的参数。
如果您添加一个新的关键字参数,您需要编写代码
deconstruct()
,将其值放入您kwargs
自己。
推荐阅读
- django - Django-Q 设置 Q_CLUSTER 'sync': True 不适用于单元测试
- ansible - 我可以在没有块的情况下在 ansible 角色/任务文件中定义变量吗?
- linux - Ansible scp 错误 - 没有这样的文件或目录
- r - tfruns 创建目录失败
- javascript - 如何从角度的对象数组中进行选择?
- python - 在 SQLAlchemy 中将 CTE 与多个引擎一起使用时出现 UnboundExecutionError
- simulation - 如何在 Anylogic 中创建具有不同标准的代理?
- ios - iOS 应用程序传输“尝试将空对象插入 com.webobjects.foundation.NSMutableDictionary”
- r - 在 r 中使用 list.files 的工作表名称
- c# - 如何在 ActionFilterAttribute 的 OnActionExecuting 中区分 C# 中的两个休息调用