2

I got a strange bug. I am failing validation if I add an email field. If validation for only 1 username field, then everything works fine. Tell me please, what am I doing wrong?

file forms.py:

class UserUpdateForm(forms.ModelForm):
    email = forms.EmailField(required=False)


    def __init__(self, user, *args, **kwargs):
        self.user = user
        super(UserUpdateForm, self).__init__(*args, **kwargs)
        if 'label_suffix' not in kwargs:
            kwargs['label_suffix'] = '*'
        self.fields['username'].widget = forms.TextInput(attrs={'class':'input-text'})
        self.fields['email'].widget = forms.EmailInput(attrs={'class':'input-text'})


    class Meta:
        model = User
        fields = ("username","email",)

file views.py:

def get_context_data(self, request):
    self.object = get_object_or_404(Profile,slug=self.kwargs['slug'])
    ctx={}
    ctx['UserUpdateForm']=UserUpdateForm(request.POST if "UserUpdateForm" in request.POST else None,instance=request.user)           
    сtx['comments']=Comments.objects.filter(profile=self.object)
    return ctx

def post(self, request, *args, **kwargs):
    if request.method=='POST':
        if "UserUpdateForm" in request.POST:
            form=UserUpdateForm(request.POST)
            if form.is_valid():
                user=User.objects.get(username=self.request.user)
                user.username=form.cleaned_data.get('username')
                user.email=form.cleaned_data.get('email')
                user.save()
                obj=Profile.objects.get(user__username=user.username)
                return HttpResponseRedirect(reverse_lazy('profile',kwargs={'slug': obj.slug},))
    return render(request,self.template_name,self.get_context_data(request))
Max
  • 55
  • 6
  • check what `print(form.errors)` logs. you can add this in the post function or in template `{{form.errors}}` in your template – hansTheFranz Oct 16 '20 at 13:22
  • @hansTheFranz: this will not work here, since the form is considered unbounded. The `request.POST` data is passed to the `user` parameter, not the data parameter. – Willem Van Onsem Oct 16 '20 at 13:23

1 Answers1

1

You construct your form with an extra parameter user:

class UserUpdateForm(forms.ModelForm):
    
    def __init__(self, user, *args, **kwargs):
        # …

so that means that the first parameter when you construct the form is the user. You thus should pass a user:

form=UserUpdateForm(request.user, request.POST)

or if you want to edit the user object:

form=UserUpdateForm(request.user, request.POST, instance=request.user)

it however does not make much sense to pass the user, since as far as one can see, you never use the .user attribute in your form.

Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555
  • Oh, I forgot to delete a user. In short, the validation works for me if the username changes and the email also changes. But if I only change the mail, the validation does not work, why? – Max Oct 16 '20 at 13:36
  • I used print (form.errors) and got this: "
    • username
      • A user with the same name already exists.
    " , but how do I change only the mail then?
    – Max Oct 16 '20 at 13:38
  • @Max: did you work with `instance=request.user`? If you do not use the `instance=...` you are creating a *new* user, and this will of course clash with the existing one. – Willem Van Onsem Oct 16 '20 at 13:38
  • How can I then get the data for the registered user? Or just create a new form, just for mail? – Max Oct 16 '20 at 13:42
  • @Max: you use `instance=request.user` in the construction of the fom. Both in the GET and POST request. Note that the data of the "old" form in the GET is lost, in the POST request you make a new request. – Willem Van Onsem Oct 16 '20 at 13:47
  • This should not be decided. When I send a form, I go straight to post and there I create a form object with request.POST and immediately try to validate it. But it won't work, because I haven't changed the username and it's the same, I have to make an exception somehow for self.request.user == form.cleaned_data.get('username'), but I can't do it. Maybe I should create a separate method to check the data from the form and the current user. If form.is_valid() or self.check_mail(self,form.cleaned_data.get('username')) something like this. What do you think of this idea? – Max Oct 16 '20 at 13:54
  • @Max: well this is not how a form works. IN that case, you should add some extra logic that checks if the username in `request.POST['username']` already exists. In case it does not, you pass `None` to the instance. But it would also complicate manners like creating a password, etc. – Willem Van Onsem Oct 16 '20 at 14:10