如何解决Djongo模型实例访问_id字段返回None的问题
问题原因
导致异常的核心问题是_id字段声明错误:你使用了Python类型标注的冒号:来定义字段,而非模型字段赋值的等号=,Django/Djongo的模型元类不会将其识别为有效模型字段。这就造成两个连锁问题:
- 实例保存后,Djongo生成的主键值没有地方回写,访问
user._id自然返回None - 二次调用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_
相关产品推荐
相关产品推荐

