Set the value of an input element in a django form - django-forms

I have a ModifyUserForm as follows:
class ModifyUserForm(forms.ModelForm):
class Meta:
model = User
fields = ('username', 'password', ...)
To let a user modify his/her data, I'd like to set the value of the password input element to be empty:
...
if request.method=='GET':
user = User.objects.get(username=username)
modifyUserForm = ModifyUserForm(instance=user)
modifyUserForm.fields['username'].widget.attrs['disabled'] = 'disabled'
modifyUserForm.fields['password'].widget.attrs['value'] = ''
Setting username input to disabled works; however, setting the value of password does not. What is the problem?

You can use the initial argument on the form field:
modifyUserForm = ModifyUserForm(instance=user, initial={'username':''})

Related

Django request.user.has_perm('aaa.add_cust')

Hello I am so confused and new to Django.
I keep getting "False" returned to me when checking user permission. but when I print the results it is clearly detects the user permission. I am trying to add a #permission_required decorator to the view but I just won't work.
##permission_required('aaa.add_cust',raise_exception=True)
view.py
def permtest_view(request):
user_name = request.user
user_perm = request.user.get_all_permissions()
user_test = request.user.has_perm('aaa.add_cust')
print(user_name,user_perm,user_test)
Models.py
class cust(models.Model):
cust = models.CharField(max_length=10)
Serializer
class cust_serializer(serializers.ModelSerializer):
class Meta:
model = cust
fileds = "__all__"
output of the print statement.
test1#test1.com {'aaa.add_cust'} False
I can get the user and the perm but when I do
user_test = request.user.has_perm('aaa.add_cust')
I get "False" back every time
I rely don't know what I am doing wrong.
I built my own customised Decorator.

How to set custom User field using allauth save_user method from POST data

So I have 2 types of users, and on one of the pages of my website I want to provide additional field cardholder and check if it's true during user sign-up via Google
class DefaultSocialAccountAdapterCustom(DefaultSocialAccountAdapter):
def save_user(self, request, sociallogin, form=None):
"""Check if it's cardholder registration"""
user = super().save_user(request, sociallogin, form)
if request.data.get('cardholder', False): # <-- how to get this POST value??
user.cardholder = True
user.save()
return user
but error I receive:
'WSGIRequest' object has no attribute 'data'
How can I read cardholder value from request during user sign up via social adapter and set cardholder field of user to True?
I solved my problem with custom serializer class of my GoogleAuthView:
class GoogleAuthView(SocialLoginView):
adapter_class = GoogleOAuth2Adapter
serializer_class = CardholderSocialLoginSerializer
here I'm setting custom field cardholder by overwriting serializer's validate() method like this:
class CardholderSocialLoginSerializer(SocialLoginSerializer):
"""Adds cardholder field for Google registration"""
cardholder = serializers.BooleanField(required=False, default=False)
def validate(self, attrs):
attrs = super().validate(attrs)
user = attrs['user']
if attrs.get('cardholder'):
user.cardholder = True
user.save()
return attrs
If you want to get the POST value for cardholder, i believe you will have to implement the following code....
if request.type == 'POST':
cardholder = request.POST['cardholder']
Hopefully it helps...

Django.contrib.auth.authenticate fail when I update the user.email field - Worked with previous credentials before email update

I created a form where logged-in users can change their email address. After the new email is saved there seems to be no matching query for the email/password combination. I checked the database entry for the specific user instance and the email was changed as expected. Even when I used django.contrib.auth.authenticate to match email/password it couldn't match. What am I doing wrong? Below is the form and view I used:
Forms.py
class UpdateEmailForm(forms.ModelForm):
password = forms.CharField(widget=forms.PasswordInput())
new_email = forms.EmailField()
class Meta:
model = User
fields = ['new_email', 'password']
def clean(self):
cleaned_data = self.cleaned_data
old_password = cleaned_data.get('password')
if not check_password(old_password, self.instance.password):
raise forms.ValidationError('Incorrect password. Please try again.')
return cleaned_data
Views.py
def user_login(request):
form = LoginForm(request.POST)
context = {'form': form}
if request.POST.get('user_login'):
email = request.POST.get('email')
password = request.POST.get('password')
user = authenticate(email=email, password=password)
if user is not None:
login(request, user)
return redirect('profile')
else:
messages.error(request, 'Email and Password does not match.')
return redirect('login')
return render(request, 'users/login.html', context)
Below is where I handle the new email form data
#login_required
def profile(request):
...
elif request.POST.get('update_email'):
data = Customer.objects.get(email=request.user.email)
email_form = UpdateEmailForm(request.POST, instance=request.user)
if email_form.is_valid():
email_form.save()
email = request.POST.get('new_email')
user = User.objects.get(email=request.user.email)
user.email = email
data.email = email
data.save()
user.save()
messages.success(request, 'Your account has been updated successfully')
return redirect('profile')
else:
return render(request, 'users/profile.html', {'data': data, 'email_form': email_form})
I fixed the problem by creating a new field named confirm_password rather than using the actual field password. The password is changed or not saved when I save the form using the actual password field
Class UpdateEmailForm(forms.Forms.ModelForm):
...
confirm_password = models.CharField(widget=forms.PasswordInput())
class Meta:
fields = ['confirm_password', 'new_email']

HyperlinkedRelatedField temporarily as read_only

I have field declared in the following way:
field = serializers.HyperlinkedRelatedField(
view_name='field-detail',
source='feature',
queryset=Field.objects.all()
)
Do you know how I can temporarily set such field as read_only ?
Unfortunately such construction doesn't work :(
serializer.Meta.extra_kwargs = {
'field': {'queryset': None, 'read_only': True}
}
it works fine, when field is declared as a ForeignKey in the Model e.g.
class Foo(models.Model):
field = models.ForeignKey(...)
class FooSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Foo
fields = ('url', 'field',...)
and then (as I mention above), or even:
serializer.Meta.read_only_fields = ('field',)
Try to pass read_only property while declaring the field when you are using HyperlinkedRelatedField
field = serializers.HyperlinkedRelatedField(
view_name='field-detail',
lookup_field='feature',
# set read_only to True
read_only=True
)
Read docs: hyperlinkedmodelserializer

Django Rest Framework custom validation errors

I'm trying to customize the default validation errors of DRF (3.x) for an account model.
My goal is to write a validation function in order to send back a customized error message.
I've tried the following:
class AccountSerializer(serializers.ModelSerializer):
password = serializers.CharField(write_only=True, required=False)
class Meta:
model = Account
fields = ('id', 'email', 'password',)
def validate_password(self, value):
"""
Validate Password.
"""
if not value:
raise serializers.ValidationError("Password cannot be empty!")
elif len(value) < 5:
raise serializers.ValidationError("Password to short...")
return value
The the length validation works fine, but the 'password is empty' validation is never thrown because the default error ('password', [u'This field may not be blank.']) is thrown before.
Is there any option to disable default errors or to force validation by my custom function first?
Thanks for help!
You can override the validation errors on a per-field basis by setting the error_messages argument when initializing the field. You need to pass a dictionary with the key being the error message name, and the value being the custom text for the error message.
In your case, you are looking to implement two error messages: required and min_length. You may also need to override blank, which is triggering your current error, unless you set allow_blank=True on the field.
So with those changes, your serializer would become
class AccountSerializer(serializers.ModelSerializer):
password = serializers.CharField(
write_only=True,
required=False,
min_length=5,
error_messages={
"blank": "Password cannot be empty.",
"min_length": "Password too short.",
},
)
class Meta:
model = Account
fields = ('id', 'email', 'password', )
I've replaced your len check with the min_length argument on the password field.
This offloads all of your validation to Django REST framework, which should make upgrades easier in the future. You can still override validate_password if you need additional custom validation, but for now I've removed it since it would be empty.
Found a solution:
I had to validate the values with the to_internal_value function because validation is run in a specific order (thanks to Kevin Brown):
order of validation
Now my improved code is as follows:
class AccountSerializer(serializers.ModelSerializer):
password = serializers.CharField(write_only=True, required=False)
class Meta:
model = Account
fields = ('id', 'email', 'password',)
def to_internal_value(self, data):
password = data.get('password')
"""
Validate Password.
"""
if not password:
raise serializers.ValidationError({'password': 'Password cannot be empty!'})
elif len(password) < 5:
raise serializers.ValidationError({'password': 'Password to short...'})
return {
'password': password
}
I hope this post is useful for somebody :)

Resources