3

I created a model (UserSettings) to extend django's User model through a OneToOneField (as recommended by the documentation):

class UserSettings(models.Model):
    user = models.OneToOneField(User, primary_key=True)
    subscribeToMails = models.BooleanField(default=True)
    [...]

I wish to offer my users a way to edit some of their profile data, some of which is stored in the User model (the email address), and the rest in the UserSettings model. How may I do that?

I thought of two ways: adding another OneToOneField in the UserSettings model for the email address field; or overriding the UpdateView get_queryset() method (but I'm not sure how). Is there a best or recommended way to do it? So far here's how my view look:

class EditUser(UpdateView):
    model = UserSettings
    fields = ('emailVisible', 'subscribeToMails', 'mpPopupNotif',
              'mpEmailNotif', 'avatar', 'quote', 'website')
    template_name = 'user/edit.html'

    def get_object(self):
        return UserSettings.objects.get(user_id=self.request.user)

    def get_success_url(self):
        return reverse_lazy('user:edit')

3 Answers 3

2

Thanks for the replies! However, since I couldn't figure out how to make this work and thought using two tables eventually resulted in too much clutter to my taste, I finally went with the easier route and subclassed AbstractUser:

# models.py
class ForumUser(AbstractUser):
    subscribeToMails = models.BooleanField(default=True)
    [...]

# views.py
class EditUser(LoginRequiredMixin, UpdateView):
    model = ForumUser
    fields = ('email', 'emailVisible', 'subscribeToMails', 'mpPopupNotif',
              'mpEmailNotif', 'avatar', 'quote', 'website')
    template_name = 'user/edit.html'
    success_url = reverse_lazy('forum:welcome')

    def get_object(self):
        return ForumUser.objects.get(username=self.request.user)

I only had to change my registration form:

# forms.py
class RegisterForm(UserCreationForm):
    email = forms.EmailField(required=True)

    class Meta:
        model = ForumUser
        fields = ('username', 'email', 'password1', 'password2')

    def clean_email(self):
        "Ensure registered emails are unique."
        email = self.cleaned_data.get('email')
        username = self.cleaned_data.get('username')
        if email and ForumUser.objects.filter(email=email).exclude(
                username=username).count():
            raise forms.ValidationError('Email address already in use.')
        return email

    def clean_username(self):
        """
        UserCreationForm method where mentions of the User model are replaced
        by the custom AbstractUser model (here, ForumUser).
        https://code.djangoproject.com/ticket/19353#no1
        and https://docs.djangoproject.com/en/1.7/_modules/django/contrib/
        auth/forms/#UserCreationForm
        """
        username = self.cleaned_data["username"]
        try:
            ForumUser.objects.get(username=username)
        except ForumUser.DoesNotExist:
            return username
        raise forms.ValidationError(
            self.error_messages['duplicate_username'],
            code='duplicate_username',
        )
Sign up to request clarification or add additional context in comments.

Comments

1

Use this solution:

mix both User and UserSettings in a form like this:

class EmployeeEditForm(forms.ModelForm):
    #fields from User model that you want to edit
    first_name = forms.CharField(required=False, label=_('First Name'))
    last_name = forms.CharField(required=False, label=_('Last Name'))

    class Meta:
        model = UserSettings
        fields = ('first_name', 'last_name', 'subscribeToMails')

You can access to User and UserSettings object in views.py like this:

user = request.user
usersettings = user.usersettings

Now you can edit User object like this:

user.first_name = request.POST['first_name']
user.last_name = request.POST['last_name']
user.save()

And edit UserSettings like this:

usersettings.subscribeToMails = request.POST['subscribeToMails']
usersettings.save() 

1 Comment

I don't understand how this is supposed to work. I passed 'context['email'] = self.request.user.email' to get_context_data in the view and replaced 'model=' by 'form_class = UserEditForm'. An email field indeed appears but empty.
-1

Formsets is the best way to go about it.

https://docs.djangoproject.com/en/dev/topics/forms/formsets/

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.