如何自定义 Python Django 模型主键自增的起始值?

这是一个很诡异的问题,搜了大半天,貌似得到的答案就是 Django 没有这个功能,问问小伙伴们可有折中的解决方案呢?

场景如:

订单的 ID 唯一且从 100000000 开始,自增+1 ,用的是 django 的 model ,不能直接修改数据库。


如何自定义 Python Django 模型主键自增的起始值?
7 回复

在 建表的 migration 里加个 ALTER TABLE 的 SQL


在Django里自定义自增主键的起始值,直接在模型里设置id字段的default参数是不行的,因为自增逻辑在数据库层。最直接的方法是在数据库迁移文件里手动修改AutoFieldsequence

假设你有个模型叫MyModel,这是最干净的做法:

  1. 先生成迁移文件:

    python manage.py makemigrations
    
  2. 找到生成的迁移文件(比如 0002_xxxx.py),修改operations列表。在CreateModel操作之后,添加一个RunSQL操作来修改序列。以PostgreSQL为例:

    # 在 migrations.py 文件中
    from django.db import migrations
    
    class Migration(migrations.Migration):
        dependencies = [
            # ... 你的依赖 ...
        ]
    
        operations = [
            migrations.CreateModel(
                name='MyModel',
                fields=[
                    ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                    # ... 其他字段 ...
                ],
            ),
            # 关键在这里:修改自增序列的起始值
            migrations.RunSQL(
                sql="ALTER SEQUENCE your_app_mymodel_id_seq RESTART WITH 1000;", # 从1000开始
                reverse_sql=migrations.RunSQL.noop, # 回滚时什么都不做
            ),
        ]
    

    注意:你需要把 your_app_mymodel_id_seq 替换成你数据库中实际的序列名。Django默认的命名规则是 {app_label}_{model_name}_id_seq。如果不确定,可以在生成迁移后,先不修改,运行python manage.py sqlmigrate your_app 0002 查看生成的SQL语句,里面会包含序列名。

  3. 运行迁移:

    python manage.py migrate
    

对于其他数据库:

  • MySQL / MariaDBALTER TABLE your_app_mymodel AUTO_INCREMENT = 1000;
  • SQLite:SQLite不支持直接修改自增起始值。通常做法是先插入一条id为999的虚拟记录(如果从1000开始),或者更彻底地在RunPython操作中连接数据库执行 UPDATE sqlite_sequence SET seq = 999 WHERE name='your_app_mymodel';。但处理起来比较麻烦,如果是新表,有时直接清空并重置序列更简单。

重要提醒:在生产环境操作已有数据的表时要极其小心,修改序列可能导致主键冲突。最好在开发环境或数据库备份后测试。

总结:用migrations.RunSQL在迁移中直接操作数据库序列最靠谱。

这个确实是可以,但是已经违反了 django model 的定义,所以还是希望只在 model 中进行实现,而不修改数据库和 migration 中的 sql 文件

我印象里 django (1.4 的源码) 的实现,创建新数据 sql insert 不带 prime key ,
我自己实现的办法是 改 数据库里这个表的 auto increment 。

可还有其他解决方案呢?

刚用到这个用于 django 的测试,你是要我预先填充这么多数据?

回到顶部