Django自定义Web3用户模型创建超级用户public_address唯一约束问题
问题解答
一、用户分离实现方式的合理性评估
该设计思路本身没有架构性问题,是可行的,但当前实现存在明显缺陷:
- 你当前为超级用户生成299以内随机整数作为public_address的方案不可行:随机范围过小,最多只能生成299个不重复值,重复概率极高,这就是你触发UNIQUE约束报错的直接原因。同时真实Web3钱包地址是符合规范的十六进制字符串,随机整数存在和真实用户地址碰撞的风险。
- 优化方案:为超级用户的public_address增加专属标识前缀,完全避免和真实钱包地址冲突,同时用足够长的随机串保证唯一性,示例:
public_address = f"su_{secrets.token_hex(30)}" - 后续开发Web3认证后端时,可以直接在认证逻辑中判断public_address前缀,超级用户走用户名密码校验,普通用户走钱包签名校验即可,逻辑清晰无耦合。
二、断点不触发的原因及其他代码问题
1. 断点未触发核心原因
你贴出的Web3User模型代码中,没有显式指定自定义管理器,Django默认会使用父类AbstractUser自带的UserManager,完全不会走你写的Web3UserManager逻辑,所以断点永远不会触发。你需要在Web3User类中补充一行代码指定管理器:
class Web3User(AbstractUser): # 新增这行指定自定义管理器 objects = Web3UserManager() public_address = models.CharField(max_length=64, unique=True) nonce = models.CharField(max_length=64)
也正因为程序走的是默认管理器,不会处理public_address字段,创建超级用户时该字段要么为空,要么重复,自然会持续触发UNIQUE约束报错。
2. 其他需要修复的代码错误
create_user方法参数设计错误:你当前create_user只接收public_address参数,但你在create_superuser调用时传入的username、password会被直接丢弃,同时你没有调用set_password方法对密码做哈希处理,就算创建了超级用户也无法正常登录。
修改后的create_user示例:
def create_user(self, public_address, username=None, password=None, **extra_fields): if not public_address: raise ValueError('Users must have a public_address') extra_fields.setdefault('is_admin', False) user = self.model( public_address=public_address, nonce=secrets.token_urlsafe(32), username=username, **extra_fields ) if password: user.set_password(password) user.save(using=self._db) return user
create_superuser需要补充默认字段校验:需要给is_staff、is_superuser设置为True,否则创建的用户没有管理员权限。
修改后的create_superuser示例:
def create_superuser(self, username, password=None, **extra_fields): extra_fields.setdefault('is_admin', True) extra_fields.setdefault('is_staff', True) extra_fields.setdefault('is_superuser', True) # 生成不会和真实钱包地址冲突的唯一public_address public_address = f"su_{secrets.token_hex(30)}" return self.create_user( public_address=public_address, username=username, password=password, **extra_fields )
内容的提问来源于stack exchange,提问作者Kyle Calica-St
相关产品推荐
相关产品推荐

