You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django ORM使用Postgres RandomUUID作为主键save后无法获取主键值

问题根因

你将PostgreSQL内置的RandomUUID函数直接作为UUIDField的默认值,该UUID是数据库执行INSERT语句时才生成的,Django ORM默认不会主动拉取数据库生成的主键值回写到实例中,因此你的实例id字段存储的是RandomUUID()函数表达式而非实际生成的UUID值。后续查询、刷新操作时,表达式会被再次解析为生成新UUID的SQL,自然无法匹配到已插入的记录。

解决方案

方案1:改用Python层面生成UUID(最推荐)

直接使用Python标准库的uuid.uuid4作为默认值,UUID在实例创建时就会生成,save前后都可以直接读取,兼容所有数据库,没有回写问题。
代码修改示例:

import uuid
from django.db import models
from django.db.models import JSONField


class NewsItem(models.Model):
    # 仅修改id字段定义即可
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    # 其余字段保持不变
    title = models.ForeignKey(RichText, models.DO_NOTHING, related_name='+',
                              null=True)
    subtitle = models.ForeignKey(RichText, models.DO_NOTHING, related_name='+',
                                 null=True)
    excerpt = models.ForeignKey(RichText, models.DO_NOTHING, related_name='+',
                                null=True)
    text = models.ForeignKey(RichText, models.DO_NOTHING, related_name='+',
                             null=True)
    image = models.ForeignKey(ImageObject, models.DO_NOTHING, related_name='+',
                              null=True)
    priority = models.IntegerField(null=True, default=0)
    frequency = models.IntegerField(null=True, default=1)
    text_effects = JSONField(blank=True, null=True, default=dict)
    scroll_speed = models.IntegerField(null=True, default=1)
    scroll_direction = models.IntegerField(null=True, default=0)
    created_at = models.DateTimeField(blank=True, null=True, auto_now_add=True)
    updated_at = models.DateTimeField(blank=True, null=True, auto_now=True)

    class Meta:
        managed = True
        db_table = 'news_items'

修改后直接操作即可:

obj = NewsItem(**params)
obj.save()
print(obj.id) # 直接输出实际生成的UUID值

方案2:保留数据库生成UUID,开启字段回写配置

如果你有业务要求必须由数据库生成UUID(比如其他系统直接操作数据库依赖该默认值),可以给UUIDField添加db_returning=True参数,Django执行INSERT时会自动带上RETURNING id子句,将数据库生成的UUID直接回写到实例中。
仅修改id字段定义即可:

id = models.UUIDField(primary_key=True, default=RandomUUID, editable=False, db_returning=True)

该配置仅支持PostgreSQL、Oracle、SQLite 3.35+等支持RETURNING语句的数据库,你当前使用PostgreSQL可以正常生效。

方案3:旧版本Django兼容方案

如果你的Django版本低于3.2不支持db_returning参数,可以在插入时添加唯一的业务标识字段,插入后通过该字段查询得到实际的UUID值。比如新增一个request_id字段存储临时唯一标识,插入后通过request_id过滤得到刚插入的记录即可。

内容的提问来源于stack exchange,提问作者Haider Ali

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 10:39:04