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

如何解决Djongo模型实例访问_id字段返回None的问题

问题原因

导致异常的核心问题是_id字段声明错误:你使用了Python类型标注的冒号:来定义字段,而非模型字段赋值的等号=,Django/Djongo的模型元类不会将其识别为有效模型字段。这就造成两个连锁问题:

  1. 实例保存后,Djongo生成的主键值没有地方回写,访问user._id自然返回None
  2. 二次调用save()时,Djongo检测不到实例有主键值,会判定为新实例执行插入操作,生成新的文档
    此外你的代码中还存在多处语法、参数匹配错误,也会引发运行异常。
解决方案

按以下步骤调整代码即可解决问题:

1. 修正模型与管理器的完整代码

from djongo.models.fields import ObjectIdField
from django.db.models import EmailField, CharField, BooleanField
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager

class UserManager(BaseUserManager):
    def create_user(self, name, email, password, mobile_number, alias=None):
        user = self.model(email=self.normalize_email(email))
        user.name = name
        user.mobile_number = mobile_number
        user.set_password(password)
        user.save(using=self._db)
        return user

    def create_superuser(self, name, email, password, mobile_number):
        # 补全create_user需要的所有必填参数
        user = self.create_user(
            name=name,
            email=email,
            password=password,
            mobile_number=mobile_number
        )
        # 修正is_staff调用错误:是字段不是方法,去掉括号
        user.is_staff = True
        user.is_superuser = True
        user.save(using=self._db)
        return user

class User(AbstractBaseUser):
    # 核心修正:将冒号改为等号,正确声明主键字段
    _id = ObjectIdField(primary_key=True)
    email = EmailField(null=False, unique=True)
    name = CharField(max_length=30)
    mobile_number = CharField(max_length=10, unique=True)
    is_active = BooleanField(default=True)
    is_staff = BooleanField(default=False)

    objects = UserManager()
    USERNAME_FIELD = "email"
    # 补全createsuperuser命令需要的额外必填字段
    REQUIRED_FIELDS = ["name", "mobile_number"]

    class Meta:
        db_table = "login"

2. 修正实例操作代码

user = User()
# 修正email字符串缺少闭合引号的问题
user.email = 'test@mail.com'
user.name = 'name'
# 修正字段赋值错误:将user_mobile_number改为user.mobile_number
user.mobile_number = '7894561236'
# 继承AbstractBaseUser必须设置密码,否则认证逻辑会报错
user.set_password('你的密码')
user.save()

print(user._id) # 此时会正常返回生成的ObjectId值,不再为None

user.name = 'newname'
user.save() # 此时会根据_id更新原有文档,不会生成新实例
可选优化

如果你没有自定义主键的特殊需求,也可以直接删除_id字段的声明,Djongo会自动生成_id作为主键,你可以通过user.pk或者user.id来访问主键值,效果完全一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.11 12:45:02