2013-07-13 71 views
4

我有Django的custom user modelMyUser有一个额外的字段保存自定义用户模型:与Django的allauth

# 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 instructions定制allauth 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的字段被正确渲染),我得到这个错误:

IntegrityError at /accounts/signup/
(1048, "Column 'age' cannot be null")

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

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

+0

我猜测是'user.age = self。clean_data ['age']'以某种方式评估为'None'。您可以验证该值吗?什么'user'参数被发送到'save'方法中? – karthikr

+0

您必须从'save'方法返回'user'也'返回用户' –

+0

@karthikr我发现'save()'方法没有执行。当在['django-allauth/allauth/account/forms.py#269']中创建新用户时引发异常(https://github.com/pennersr/django-allauth/blob/master/allauth/account /forms.py#L269)。 – illagrenan

回答

6

虽然它有点晚了,但如果它帮助某人。

你需要通过继承DefaultAccountAdapter和设置

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() 

创建自己的自定义AccountAdapter,你也需要定义设置如下:

ACCOUNT_ADAPTER = 'api.adapter.UserAccountAdapter' 

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

DefaultAdapter为Django的allauth节省了用户,所以如果你在你的自定义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 

然后你可以装点您的自定义SignupForm与@transaction.atomic

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

这现在是正确的答案 – Jakobovski

+0

编辑添加一个示例,它可能有一个'CustomAdapter' :) – danidee

1

旁注

使用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' 

也许这是没有关系的,但我认为它值得注意。

+0

我想强制使用属性'age',但是django-allauth是[试图保存'MyUser'](https://github.com/pennersr/django-allauth/blob/master/allauth/account/forms。 py#L269)仅限默认字段。并感谢'get_user_model'函数,我不知道。 – illagrenan

0

我想你应该定义字段包含年龄,像这样在SignupForm类元属性和字段的设置列表:

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

,如果它不工作,看 this