Reputation: 23
When user updates profile with username which is already in use ,message appear of "A user with that username already exists." but username on profile is changed to which user requested. for example: if user with username test001 update profile with already taken username "test0012"
this will happen:
Notice:username is updated with "test0012"
Code in frontend for username:
<h2 id="user-name" class="account-heading user__name">@{{ user.username }}</h2>
also going on "my posts" will redirect to posts of user "test0012".
code for profile and update:
@login_required
def profile(request):
if request.method=="POST":
u_form=UserUpdateForm(request.POST,instance=request.user)#,op_email=request.user.email)
p_form=ProfileUpdateForm(request.POST,request.FILES,instance=request.user.profile)
if u_form.is_valid() and p_form.is_valid():
u_form.save()
p_form.save()
messages.success(request,f'Your Account has been updated!')
#changing email on profile
tusername=u_form.cleaned_data.get('username')
temail=u_form.cleaned_data.get('email')
registeruser=User.objects.get(username=tusername)
registeruser.email=temail
registeruser.save()
return redirect('profile')
else:
u_form=UserUpdateForm(instance=request.user)
p_form=ProfileUpdateForm(instance=request.user.profile)
userupdateform code:
class UserUpdateForm(forms.ModelForm):
email=forms.EmailField()
username=forms.CharField(required=True,validators=[username_check,])
class Meta:
model =User
fields =['username','email']
ProfileUpdateForm:
class ProfileUpdateForm(forms.ModelForm):
class Meta:
model=Profile
fields=['image']
username_check:
def username_check(someusername):
if someusername!=someusername.lower():
raise forms.ValidationError("Only Lower case allowed.")
Upvotes: 1
Views: 888
Reputation: 21787
The model form first does it's own cleaning / validation, after which it assigns this data to the instance that you passed to it and calls that instance's full_clean
method which is what gives you the error A user with that username already exists
. But as you notice this is already too late as the instance is already modified, although this does not get saved to the database you are displaying the same instance.
The solution to this is to get a copy of the user instance from the database just to pass it to the form, so that the instance associated with the request stays unchanged and clean:
from django.contrib.auth import get_user_model
UserModel = get_user_model()
@login_required
def profile(request):
user = UserModel.objects.get(pk=request.user.pk)
if request.method == "POST":
u_form = UserUpdateForm(request.POST, instance=user)
p_form = ProfileUpdateForm(request.POST, request.FILES, instance=user.profile)
...
else:
u_form = UserUpdateForm(instance=user)
p_form = ProfileUpdateForm(instance=user.profile)
Upvotes: 4