I have a profile form that shows email, user name and first name. user only allowed to change first name field and the others are read only, if user change HTML value in email and username then submit it, it returns error but fill the fields with invalid value entered. I tried create a new instance of form and render it but it no longer shows the error. The thing I want is to reset invalid data then display the error.
forms.py
class UserEditForm(forms.ModelForm): email = forms.EmailField( label='Account email (can not be changed)', max_length=200, widget=forms.TextInput( attrs={'class': 'form-control mb-3', 'placeholder': 'email', 'id': 'form-email', 'readonly': 'readonly'})) user_name = forms.CharField( label='Username', min_length=4, max_length=50, widget=forms.TextInput( attrs={'class': 'form-control mb-3', 'placeholder': 'Username', 'id': 'form-username', 'readonly': 'readonly'})) first_name = forms.CharField( label='First name', min_length=4, max_length=50, widget=forms.TextInput( attrs={'class': 'form-control mb-3', 'placeholder': 'Firstname', 'id': 'form-firstname'})) class Meta: model = UserBase fields = ('email', 'user_name', 'first_name',) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.fields['user_name'].required = True self.fields['email'].required = True def clean_user_name(self): username = self.cleaned_data['user_name'] if username != self.instance.user_name: raise forms.ValidationError('Sorry, you can not change your username') return username def clean_email(self): email = self.cleaned_data['email'] if email != self.instance.email: raise forms.ValidationError('Sorry, you can not change your email') return email
views.py
class ChangeUserDetail(SuccessMessageMixin, LoginRequiredMixin, FormView): template_name = 'accounts/user/default_form.html' success_url = reverse_lazy('accounts:dashboard') success_message = "Username changed successfully" form_class = UserEditForm def get_form(self, form_class=form_class): return form_class(instance = self.request.user, **self.get_form_kwargs()) def post(self, request, *args, **kwargs): form = self.get_form() if form.is_valid(): return self.form_valid(form) else: form = self.form_class(instance=self.request.user) return self.form_invalid(form) def form_valid(self, form): user = form.save() return super().form_valid(form) def form_invalid(self, form): return super().form_invalid(form)
html page
<div class="row"> <div class="col-md-6"> {% if form.errors %} <div class="alert alert-danger" role="alert"> {{form.errors}} </div> {% endif %} <form method="post"> {%csrf_token%} {{form|crispy}} <div class="form-group"> <button class="btn btn-outline-info" type="submit">{{title}}</button> </div> </form> </div> </div>
Advertisement
Answer
After a few searches I found that I can address my issue by adding disabled=True attribute to my fields so if user try to change it database will ignore change and returns the initial value as it said in Django documentation
class UserEditForm(forms.ModelForm): email = forms.EmailField( label='Account email (can not be changed)', max_length=200, disabled=True, widget=forms.TextInput( attrs={'class': 'form-control mb-3', 'placeholder': 'email', 'id': 'form-email', 'readonly': 'readonly'})) user_name = forms.CharField( label='Username', disabled=True, min_length=4, max_length=50, widget=forms.TextInput( attrs={'class': 'form-control mb-3', 'placeholder': 'Username', 'id': 'form-username', 'readonly': 'readonly'}))