shacker
shacker

Reputation: 15391

Allow changing of User fields (like email) with django-profiles

Django lets you create a model foreign-keyed to User and define it in settings as the official "profile" model holding additional data for user accounts. django-profiles lets you easily display/create/edit that profile data. But the user's primary email address is part of their main account, not part of their extended profile. Therefore when you put

{{ form }}

in the profile/edit_profile template, the primary email address does not show up. You can retrieve it manually with

{{ user.email }}

but changes to it aren't saved back to the account upon submit of course. I'm assuming a custom ModelForm has been created, such as:

class ProfileForm(ModelForm):

  class Meta:
      model = Parent
      exclude = ('family','user','board_pos','comm_job',)

and that ProfileForm is being passed to django-profiles' view code with a urlconf like:

('^profiles/edit', 'profiles.views.edit_profile', {'form_class': ProfileForm,}),

The same problem would come up if you wanted to let users change their first or last names. What's the best way to let users change their own email addresses or names when using django-profiles?

Upvotes: 4

Views: 5783

Answers (3)

shacker
shacker

Reputation: 15391

Here's the solution we ended up using:

# urls.py
    # First match /profiles/edit before django-profiles gets it so we can pass in our custom form object.
    ('^profiles/edit', 'profiles.views.edit_profile', {'form_class': ProfileForm,}),
    (r'^profiles/', include('profiles.urls')),

Now we override the save method in the form itself, so that when the form is saved, the email address is pushed into the saving user's User object at the same time. Graceful.

# forms.py , trimmed for brevity

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

    email = forms.EmailField(label="Primary email")

    class Meta:
      model = Parent

    def save(self, *args, **kwargs):
      """
      Update the primary email address on the related User object as well. 
      """
      u = self.instance.user
      u.email = self.cleaned_data['email']
      u.save()
      profile = super(ProfileForm, self).save(*args,**kwargs)
      return profile

Works perfectly. Thanks mandric.

Upvotes: 8

Andriy Drozdyuk
Andriy Drozdyuk

Reputation: 61131

I think that implementing a Separate page just for change of email is best, since it would need to be verified etc...

If you would like to enable users to modify all their profile info together with their main email address, then you need to create your own Form (ModelForm will not work here). I suggest you start doing this and post a question when you get stuck.

Start by copying all the fields out of django-profile model into your custom form, and add the users primary email field.

You will have to "override" the django-profile edit url and basically copy the html template if there is one.

Another option (bad) would be to hack django-profiles app and change it there. But that will, likely, introduce a lot of bugs, and will render your app unapgradable.

Upvotes: 2

AlbertoPL
AlbertoPL

Reputation: 11529

I think the easiest way would definitely be to use a form. Use the form to display their current email address (which they could change), and then use your view to extract the request, retrieve the appropriate profile belonging to that user by matching some other parameter you could pass to the template, and then storing the new data and saving the model.

Upvotes: 1

Related Questions