为使用UUIDField作为主键的Django模型添加非主键AutoField或serial字段
解决Django UUID主键下添加自增字段的问题
我之前也碰到过一模一样的场景——用UUID做主键,但业务上需要一个连续自增的编号,下面是亲测有效的解决方案:
1. 正确定义模型
先保留UUID作为主键,同时添加自增字段,关键要设置blank=True(允许Admin表单留空)和null=False(数据库字段不允许为空):
import uuid from django.db import models class YourModel(models.Model): id = models.UUIDField( primary_key=True, default=uuid.uuid4, editable=False ) # 业务自增编号 number = models.IntegerField( unique=True, blank=True, null=False ) def __str__(self): return f"{self.number} - {self.id}"
2. 生成并修改迁移文件
先执行python manage.py makemigrations生成初始迁移,然后打开生成的迁移文件,添加创建序列和设置字段默认值的SQL操作:
from django.db import migrations, models import uuid class Migration(migrations.Migration): dependencies = [ # 这里填写你的依赖迁移,比如('yourapp', '0001_initial') ] operations = [ migrations.CreateModel( name='YourModel', fields=[ ('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), ('number', models.IntegerField(null=False, unique=True)), ], ), # 创建序列,起始值设为100000 migrations.RunSQL( sql="CREATE SEQUENCE yourmodel_number_seq START 100000;", reverse_sql="DROP SEQUENCE IF EXISTS yourmodel_number_seq;" ), # 给number字段设置默认值为序列的下一个值 migrations.RunSQL( sql="ALTER TABLE yourmodel ALTER COLUMN number SET DEFAULT nextval('yourmodel_number_seq');", reverse_sql="ALTER TABLE yourmodel ALTER COLUMN number DROP DEFAULT;" ), ]
3. 执行迁移
运行python manage.py migrate完成数据库变更。
4. 验证效果
现在通过Admin后台添加对象时,不需要手动输入number字段,数据库会自动从100000开始生成自增编号,完全不会和UUID主键冲突。
为什么之前的db_type='serial'没生效?
PostgreSQL的serial类型本质是IntegerField + 自动创建序列 + 默认值为nextval,但直接在Django字段里设置db_type='serial'时,Django不会自动处理Admin表单的空白提交逻辑:如果没设置blank=True,Admin会强制要求输入该字段,否则会传入null覆盖数据库的默认值,导致存储为null。上面的方案手动控制了序列和默认值,同时通过blank=True让Admin允许留空,完美解决了这个问题。
内容的提问来源于stack exchange,提问作者Basel J. Hamadeh
相关产品推荐
相关产品推荐

