djangodjango-formsdjango-profiles

Django form checkbox to change a value in UserProfile


I'm using Django-Profiles with Django 1.4, and I need a way to unsubscribe a user, so they can stop getting emails.

One of the fields in my UserProfile model is user_type, and I have a USER_TYPES list of choices. To keep users in the system, even if they unsubscribe, I decided to have one of the USER_TYPES be InactiveClient, and I'd include a checkbox like so:

Models.py:

USER_TYPES = (
    ('Editor', 'Editor'),
    ('Reporter', 'Reporter'),
    ('Client', 'Client'),
    ('InactiveClient', 'InactiveClient'),
    ('InactiveReporter', 'InactiveReporter'),
)

class UserProfile(models.Model):
    user = models.OneToOneField(User, unique=True)
    user_type = models.CharField(max_length=25, choices=USER_TYPES, default='Client')
    ... etc.

forms.py

class UnsubscribeForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super(UnsubscribeForm, self).__init__(*args, **kwargs)
        try:
            self.initial['email'] = self.instance.user.email
            self.initial['first_name'] = self.instance.user.first_name
            self.initial['last_name'] = self.instance.user.last_name
        except User.DoesNotExist:
            pass
    email = forms.EmailField(label='Primary Email')
    first_name = forms.CharField(label='Editor first name')
    last_name = forms.CharField(label='Editor last name')    
    unsubscribe = forms.BooleanField(label='Unsubscribe from NNS Emails')

    class Meta:
        model = UserProfile
        fields = ['first_name','last_name','email','unsubscribe']

    def save(self, *args, **kwargs):
        u = self.instance.user
        u.email = self.cleaned_data['email']
        u.first_name = self.cleaned_data['first_name']
        u.last_name = self.cleaned_data['last_name']
        if self.unsubscribe:
            u.get_profile().user_type = 'InactiveClient'
        u.save()
        client = super(UnsubscribeForm, self).save(*args,**kwargs)
        return client

Edit: I've added additional code context. if self.unsubscribe: is in save() override. Should that be somewhere else? Thank you.

Edit2: I've tried changing UnsubscribeForm in several ways. Now I get a 404, No User matches the given query. But the view function being called works for other forms, so I'm not sure why?

urls.py

urlpatterns = patterns('',
    url('^client/edit', 'profiles.views.edit_profile',
        {
            'form_class': ClientForm,
            'success_url': '/profiles/client/edit/',
        },
        name='edit_client_profile'),
    url('^unsubscribe', 'profiles.views.edit_profile',
        {
            'form_class': UnsubscribeForm,
            'success_url': '/profiles/client/edit/',
        },
        name='unsubscribe'),
        )

These two urls are calling the same view, just using a different form_class.

Edit3: So I don't know why, but when I removed the trailing slash from the unsubscribe url, the form finally loads. But when I submit the form, I still get an error: 'UnsubscribeForm' object has no attribute 'unsubscribe' If anyone could help me understand why a trailing slash would cause the 404 error (No User matches the given query) I wouldn't mind knowing. But as of now, the form loads, but doesn't submit, and the trace ends on this line of my form:

if self.unsubscribe:

Solution

  • Answering my own question again. On ModelForms, you can add form elements that don't exist in the model, and access the value of those fields by accessing self.cleaned_data['form_element_name'] in the save method.

    This is what my save method looks like:

    def save(self, *args, **kwargs):
        u = self.instance.user
        p = self.instance.user.get_profile()
        u.email = self.cleaned_data['email']
        u.first_name = self.cleaned_data['first_name']
        u.last_name = self.cleaned_data['last_name']
        if self.cleaned_data['unsubscribe']:
            p.user_type = 'InactiveClient'
        u.save()
        p.save()
        client = super(UnsubscribeForm, self).save(*args,**kwargs)
        return client