4

I'm trying to create an update profile page for my custom User model. In my model, my email field is set to be unique.

class User(UserBase):
     ...
     email = models.EmailField(
            max_length=100,
            unique=True,
            blank=True,
            verbose_name='email address',
        )

Then in my view I have:

class UpdateProfileView(LoginRequiredMixin, UpdateView):
    template_name = 'accounts/update-profile.html'
    form_class = UpdateProfileForm
    model = User

The only thing that UpdateProfileForm does is check that the old password is different from the new one in the clean method.

My issue is that when I save the form I'm getting the error message User with this Email address already exists.. Since it's an update view and saving a unique field that hasn't changed shouldn't it not throw this error? If this is the correct behavior, then how do I save the form and ignore the email address if it hasn't changed.

Thanks for the help in advance.

imns
  • 4,996
  • 11
  • 57
  • 80
  • Am I taking crazy pills, is this not a thing or a dumb question? – imns Feb 07 '14 at 15:19
  • No one has any feedback on this? – imns Mar 18 '14 at 15:30
  • 1
    Why don't you show us the `UpdateProfileForm` so we can get a better idea. – brianmearns Mar 18 '14 at 15:34
  • 3
    Right from the `form.save` [docs](https://docs.djangoproject.com/en/dev/topics/forms/modelforms/#the-save-method): "A subclass of ModelForm can accept an existing model instance as the keyword argument instance; if this is supplied, save() will update that instance. If it’s not supplied, save() will create a new instance of the specified model." Are you using the `instance` argument? – Two-Bit Alchemist Mar 18 '14 at 15:39
  • I would assume `UpdateView` does this behind the scenes. At least that is the behavior I would expect. – imns Mar 18 '14 at 16:48
  • 1
    Does it work when you comment out the `form_class`? – Chris Wesseling Mar 18 '14 at 19:01

3 Answers3

2

Remove blank=True from your User Model definition. The field definition is null=False by default and additionally you specify the field must be unique—it's a important field—so you don't want your form validation to allow blank values. Here is the Django documentation on those attributes. blank is entirely a form validation thing. That alone might fix the error.

Unless you have custom form logic/validation, you don't need the form_class attribute on your UpdateProfileView. From the docs: "These generic views will automatically create a ModelForm". (There is even an UpdateView example).

See if the view works without form_class and if it does then examine your UpdateProfileForm code.

JCotton
  • 11,650
  • 5
  • 53
  • 59
0

Here are some suggestions/alternatives:

  1. If you stop using Generic Views (i.e. UpdateProfileView), you can then do the following steps in your logic view: if the request is a POST, take the data from the form and update your Model (How to update fields in a model without creating a new record in django?)

  2. Why don't you use a ModelForm instead? https://docs.djangoproject.com/en/dev/topics/forms/modelforms/

  3. Why don't you work with User from django.contrib.auth.models? https://docs.djangoproject.com/en/dev/topics/auth/default/#user-objects

  4. Finally, have you considered working with this already built Django registration app? http://www.michelepasin.org/blog/2011/01/14/setting-up-django-registration/

Community
  • 1
  • 1
Mihai Zamfir
  • 2,167
  • 4
  • 22
  • 37
0
  1. Never use blank=True and unique=True, its senseless. If you want to make this field is not required in form, just do.

    class Form(forms.Form):
         ...
    
         def __init__(self, *args, **kwargs):
              super().__init__(*args, **kwargs)
              self.fields['unique_field].required = False 
    
  2. In addition to previous answer, when u use blank=True and unique=True, the "Is already exits ... blah bla" its correct behavior, coz form accepting empty string as value and its already exists. You need to override clean_field method:

    class Form(forms.Form):
        ...
    
        def clean_unique_id(self):
            """
            Take new value or if its '' e.g. None take initial value 
            """
            return self.data['unique_id'] or self.initial['unique_id']
    
Kyrylo Perevozchikov
  • 1,657
  • 2
  • 10
  • 6