En Django, ¿cómo puedo crear un usuario y un perfil de usuario al mismo tiempo desde un solo formulario?

Estoy usando la versión extendida de UserCreationForm para agregar usuarios a través de mi propia plantilla, que funciona bien.

También me gustaría incluir, como parte de la misma plantilla de formulario, un campo personalizado de mi modelo de perfil de usuario, para que cuando se cree el usuario también se cree un perfil de usuario con mi campo personalizado.

Mi enfoque para esto ha sido utilizar dos formularios y combinarlos en una plantilla con un solo botón de envío.

El formulario se muestra exactamente como quería, y devuelve los errores de validación correctamente, pero previsiblemente se cae cuando se trata de guardar en la base de datos. Cuando llamo a save () en el formulario de usuario, se crea el usuario, pero, por supuesto, cuando bash guardar el formulario de perfil de usuario, se genera un error porque el usuario aún no existe, por lo que no tiene un usuario asociado.

Aunque creo que entiendo la causa de mi problema, no sé cómo solucionarlo, ni siquiera estoy seguro de si el enfoque que he tomado es correcto.

He incluido todo mi código a continuación, incluido el modelo, así como los formularios y la vista, en caso de que esto ayude a alguien a comprender mejor lo que estoy tratando de hacer:

Clase UserProfile (models.py)

LEVEL = ( ('admin', 'administrator'), ('team', 'team leader'), ('member', 'team member'), ) class UserProfile(models.Model): user = models.ForeignKey(User, unique=True) level = models.CharField(choices=LEVEL, max_length=20) 

Clases UserCreationForm y UserProfileForm (forms.py)

 class UserCreationFormExtended(UserCreationForm): def __init__(self, *args, **kwargs): super(UserCreationFormExtended, self).__init__(*args, **kwargs) self.fields['first_name'].required = True self.fields['last_name'].required = True class Meta: model = User fields = ('username', 'email', 'first_name', 'last_name') class UserProfileForm(forms.ModelForm): def __init__(self, *args, **kwargs): super(UserProfileForm, self).__init__(*args, **kwargs) self.fields["level"].choices = ( ('admin', 'administrator'), ('team', 'team leader'), ('member', 'team member') ) class Meta: model = UserProfile 

vista use_add (views.py)

 def user_add(request): if request.method == 'POST': uform = UserCreationFormExtended(request.POST) pform = UserProfileForm(request.POST) if uform.is_valid(): uform.save() pform.save() return render_to_response('user/add_success.html', context_instance=RequestContext(request)) else: return render_to_response('user/add.html', { 'uform' : uform, 'pform' : pform }, context_instance=RequestContext(request)) else: uform = UserCreationFormExtended() pform = UserProfileForm() return render_to_response('user/add.html', { 'uform' : uform, 'pform' : pform }, context_instance=RequestContext(request)) 

Primero, agregue exclude = ('user',) a la clase Meta para ProfileForm. Entonces, en su opinión:

 user_valid = uform.is_valid() profile_valid = pform.is_valid() if user_valid and profile_valid: user = uform.save() profile = pform.save(commit=False) profile.user = user profile.save() 

Aunque se me ocurre que como solo tiene un campo en el formulario de perfil, una forma más fácil de hacerlo es olvidarlo por completo, y simplemente agregar el campo al formulario de usuario:

 class UserCreationFormExtended(UserCreationForm): level = forms.ChoiceField(choices=LEVEL, max_length=20) ... etc... if uform.is_valid(): user = uform.save() profile = Profile.objects.create(user=user, level=uform.cleaned_data['level'])) 

Hay una solución similar que encontré aquí: http://sontek.net/blog/detail/extending-the-django-user-model

Básicamente, usted solo extiende el formulario predeterminado UserCreationForm pero conservando el mismo nombre. Al hacerlo de esta manera, no tiene que agregar nuevas vistas ni nada de eso, funciona a la perfección con la forma en que los documentos de Django le dicen que haga Perfiles de usuario.

Francamente, no entiendo por qué explican cómo agregar los campos a la página de administración, y luego no le dicen cómo usar esos campos en cualquier lugar.