Postgres下Django调用表单clean方法报can't adapt type 'User'错误
根因分析
你的猜测方向是正确的,问题核心就是不该在form.is_valid()执行完成后手动调用字段的clean_username_or_email方法,具体逻辑如下:
- Django表单执行
is_valid()的过程中,已经自动跑了一遍所有字段的校验逻辑,你的clean_username_or_email方法会被调用一次,返回的User实例会被存入form.cleaned_data["username_or_email"],覆盖了原本用户输入的字符串值。 - 你后续手动二次调用
clean_username_or_email时,方法中取到的self.cleaned_data["username_or_email"]已经是User对象,不是用户输入的用户名/邮箱字符串。 - 此时用这个User对象作为参数执行
User.objects.get(Q(username__iexact=data) | Q(email__iexact=data))查询,相当于直接把User实例传入SQL参数:- Sqlite对参数类型校验非常宽松,会自动调用User实例的
__str__方法转成字符串执行查询,只要字符串匹配就能正常返回结果,所以Sqlite环境不会报错。 - Postgres对参数类型校验严格,无法识别User类型的查询参数,直接抛出
can't adapt type 'User'的错误,这就是两个数据库表现不一致的原因。
- Sqlite对参数类型校验非常宽松,会自动调用User实例的
修复方案
不需要手动调用字段的clean方法,直接从表单的cleaned_data字典中取已经校验完成的结果即可,修改视图中if form.is_valid()代码块内的对应行:
把
user = form.clean_username_or_email()
替换为
user = form.cleaned_data["username_or_email"]
内容的提问来源于stack exchange,提问作者Raymond DeVries
相关产品推荐
相关产品推荐

