【问题标题】:Saving custom user model with django-allauth使用 django-allauth 保存自定义用户模型
【发布时间】:2013-07-12 03:42:06
【问题描述】:

我有 django custom user model MyUser 有一个额外的字段:

# models.py
from django.contrib.auth.models import AbstractUser

class MyUser(AbstractUser):
    age = models.PositiveIntegerField(_("age"))

# settings.py
AUTH_USER_MODEL = "web.MyUser"

我也有根据to these instructionscustom all-auth Signup form class:

# forms.py
class SignupForm(forms.Form):
    first_name = forms.CharField(max_length=30)
    last_name = forms.CharField(max_length=30)
    age = forms.IntegerField(max_value=100)

    class Meta:
        model = MyUser

    def save(self, user):
        user.first_name = self.cleaned_data['first_name']
        user.last_name = self.cleaned_data['last_name']
        user.age = self.cleaned_data['age']
        user.save()

# settings.py
ACCOUNT_SIGNUP_FORM_CLASS = 'web.forms.SignupForm'

提交SignupForm(属性MyUser.age 的字段正确呈现)后,我收到此错误:

/accounts/signup/ 处的 IntegrityError
(1048, "列'年龄'不能为空")

存储自定义用户模型的正确方法是什么?

django-allauth:0.12.0; django:1.5.1; Python 2.7.2

【问题讨论】:

  • 我的猜测是 user.age = self.cleaned_data['age'] 正在评估 None 不知何故..你能验证这个值吗?什么是user 参数被发送到save 方法?
  • 您必须从save 方法也返回user return user
  • @karthikr 我发现方法save() 没有执行。在django-allauth/allauth/account/forms.py#269 中创建新用户时引发异常。
  • IntegrityError "列'年龄'不能为空"
  • @illagrenan 我建议覆盖表单的 clean 而不是 save 方法。这样,错误可以在保存之前被捕获。我还是觉得def save(self, user)不对

标签: python django django-models django-allauth


【解决方案1】:

虽然有点晚了,但万一它对某人有帮助。

您需要通过继承 DefaultAccountAdapter 并设置您自己的自定义 AccountAdapter

class UserAccountAdapter(DefaultAccountAdapter):

    def save_user(self, request, user, form, commit=True):
        """
        This is called when saving user via allauth registration.
        We override this to set additional data on user object.
        """
        # Do not persist the user yet so we pass commit=False
        # (last argument)
        user = super(UserAccountAdapter, self).save_user(request, user, form, commit=False)
        user.age = form.cleaned_data.get('age')
        user.save()

您还需要在设置中定义以下内容:

ACCOUNT_ADAPTER = 'api.adapter.UserAccountAdapter'

这也很有用,如果您有一个自定义的 SignupForm 在用户注册期间创建其他模型,并且您需要进行原子事务以防止任何数据保存到数据库,除非它们都成功。

django-allauth 的 DefaultAdapter 保存用户,因此如果您在自定义 SignupForm 的 save 方法中有错误,用户仍将被持久保存到数据库中。

因此,对于遇到此问题的任何人,您的 CustomAdpater 看起来像这样

类 UserAccountAdapter(DefaultAccountAdapter):

    def save_user(self, request, user, form, commit=False):
        """
        This is called when saving user via allauth registration.
        We override this to set additional data on user object.
        """
        # Do not persist the user yet so we pass commit=False
        # (last argument)
        user = super(UserAccountAdapter, self).save_user(request, user, form, commit=commit)
        user.age = form.cleaned_data.get('age')
        # user.save() This would be called later in your custom SignupForm

然后您可以使用@transaction.atomic 装饰您的自定义注册表单

@transaction.atomic
def save(self, request, user):
    user.save() #save the user object first so you can use it for relationships
    ...

【讨论】:

  • 编辑添加了一个示例,其中可能有一个CustomAdapter :)
  • 感谢您的回答,但是有没有办法只更新allauth中的社交帐户模型而不是用户模型,save_user 是否更新用户模型?
  • 我们会将这个适配器放在什么文件中?
【解决方案2】:

旁注

使用 Django 1.5 自定义用户模型,最佳实践是使用get_user_model 函数:

from django.contrib.auth import get_user_model

# forms.py
class SignupForm(forms.Form):
    first_name = forms.CharField(max_length=30)
    last_name = forms.CharField(max_length=30)
    age = forms.IntegerField(max_value=100)

    class Meta:
        model = get_user_model() # use this function for swapping user model

    def save(self, user):
        user.first_name = self.cleaned_data['first_name']
        user.last_name = self.cleaned_data['last_name']
        user.age = self.cleaned_data['age']
        user.save()

# settings.py
ACCOUNT_SIGNUP_FORM_CLASS = 'web.forms.SignupForm'

也许它不相关,但我认为它会值得注意。

【讨论】:

  • 我想让属性 age 强制,但 django-allauth 是 trying to save MyUser 只有默认字段。感谢get_user_model 功能,我不知道。
【解决方案3】:

我认为您应该在 SignupForm 的 Meta 类中定义 fields 属性并设置包含年龄的字段列表,如下所示:

class SignupForm(forms.Form):
...
   class Meta:
      model = MyUser
      fields = ['first_name', 'last_name', 'age']

如果它不起作用,请查看 this

【讨论】:

    猜你喜欢
    • 2023-03-26
    • 2013-09-22
    • 1970-01-01
    • 1970-01-01
    • 2014-02-15
    • 2021-01-25
    • 2020-08-23
    • 2016-03-13
    • 2018-08-19
    相关资源
    最近更新 更多