Natim
Natim

Reputation: 18102

How to create a UserProfile form in Django with first_name, last_name modifications?

If think my question is pretty obvious and almost every developer working with UserProfile should be able to answer it.

However, I could not find any help on the django documentation or in the Django Book.

When you want to do a UserProfile form in with Django Forms, you'd like to modify the profile fields as well as some User field.

But there is no forms.UserProfileForm (yet?)!

How do you do that?

Upvotes: 25

Views: 26819

Answers (7)

user2486909
user2486909

Reputation: 11

This is something i used in one my projects long back hopefully it should help out the others googling this problem .

class SignUpForm(forms.ModelForm):
    first_name = forms.CharField(max_length = 30)
    last_name = forms.CharField(max_length = 30)
    username = forms.CharField(max_length = 30)
    password = forms.CharField(widget = forms.PasswordInput)
    password1 = forms.CharField(widget = forms.PasswordInput)
    class Meta:
        model = UserProfile
        exclude = ['user']

    def clean_username(self): # check if username does not exist before
        try:
            User.objects.get(username=self.cleaned_data['username']) #get user from user model
        except User.DoesNotExist :
            return self.cleaned_data['username']

        raise forms.ValidationError("This user exist already choose an0ther username")



    def clean(self, *args , **kwargs):
        super(SignUpForm).clean(*args ,**kwargs) # check if password 1 and password2 match each other
        if 'password1' in self.cleaned_data and 'password2' in self.cleaned_data:#check if both pass first validation
            if self.cleaned_data['password1'] != self.cleaned_data['password2']: # check if they match each other
                raise forms.ValidationError("Passwords don't match each other")

        return self.cleaned_data
    def save(self): # create new user
        new_user = User.objects.create_user(username=self.cleaned_data['username'],password=self.cleaned_data['password1'],email=self.cleaned_data['email'])
        new_user.first_name = self.cleaned_data['first_name']
        new_user.last_name = self.cleaned_data['last_name']
        new_user.save()
        UserProf =  super(SignUpForm,self).save(commit = False)
        UserProf.user = new_user
        UserProf.save()
        return UserProf

Upvotes: 1

Adam Nelson
Adam Nelson

Reputation: 8090

You can also try to use the django-basic-apps project which has a profiles app:

https://github.com/nathanborror/django-basic-apps

Upvotes: 1

Natim
Natim

Reputation: 18102

Here is how I finally did :

class UserProfileForm(forms.ModelForm):
    first_name = forms.CharField(label=_(u'Prénom'), max_length=30)
    last_name = forms.CharField(label=_(u'Nom'), max_length=30)

    def __init__(self, *args, **kw):
        super(UserProfileForm, self).__init__(*args, **kw)
        self.fields['first_name'].initial = self.instance.user.first_name
        self.fields['last_name'].initial = self.instance.user.last_name

        self.fields.keyOrder = [
            'first_name',
            'last_name',
            ...some_other...
            ]

    def save(self, *args, **kw):
        super(UserProfileForm, self).save(*args, **kw)
        self.instance.user.first_name = self.cleaned_data.get('first_name')
        self.instance.user.last_name = self.cleaned_data.get('last_name')
        self.instance.user.save()

    class Meta:
        model = UserProfile

Upvotes: 34

theycallmemorty
theycallmemorty

Reputation: 12962

I stumbled across this today and after some googling I found a solution that is a bit cleaner in my opinion:

#in forms.py
class UserForm(forms.ModelForm):
    class Meta:
        model = User
        fields = ["username", "email"]

class UserProfileForm(forms.ModelForm):
    class Meta:
        model = UserProfile

#in views.py
def add_user(request):
    ...
    if request.method == "POST":
        uform = UserForm(data = request.POST)
        pform = UserProfileForm(data = request.POST)
        if uform.is_valid() and pform.is_valid():
            user = uform.save()
            profile = pform.save(commit = False)
            profile.user = user
            profile.save()
            ....
    ...

#in template
<form method="post">
    {{ uform.as_p }}
    {{ pform.as_p }}
    <input type="submit" ...>
</form>

Source

Upvotes: 41

Tom
Tom

Reputation: 22841

Why not have two model forms on the back-end and just present them as a single form in your template? Drop the name fields from your UserProfileForm and create a second model form for the user object?

Upvotes: 0

wunki
wunki

Reputation: 663

This is how I did it in the current trunk (Revision: 11804). The solution of Natim was not working for me.

In admin.py:

class ProfileAdmin(admin.ModelAdmin):
    form = ProfileForm

    def save_model(self, request, obj, form, change):
        obj.user.first_name = form.cleaned_data['first_name']
        obj.user.last_name = form.cleaned_data['last_name']
        obj.user.save()
        obj.save()

In forms.py:

class ProfileForm(forms.ModelForm):
    first_name = forms.CharField(max_length=256)
    last_name = forms.CharField(max_length=256)

    def __init__(self, *args, **kwargs):
        super(ProfileForm, self).__init__(*args, **kwargs)
        try:
            self.fields['first_name'].initial = self.instance.user.first_name
            self.fields['last_name'].initial = self.instance.user.last_name
        except User.DoesNotExist:
            pass

    class Meta:
         fields = ['first_name', 'last_name', ...etc.]

Upvotes: 5

shanyu
shanyu

Reputation: 9716

I take it normal that you don't find any information in the docs as you merge two models into a single form.

Alternatively and maybe very obviously you can: Create two modelforms, one for the user and the other for the userprofile. Set the userprofile modelform to display only firstname and lastname. Put both forms in the same template within a single <form> tag. When it is submitted, call the save methods of each form.

Upvotes: 0

Related Questions