I'm trying to edit django-registration's RegistrationFormUniqueEmail form, which currently looks like the following:
class RegistrationFormUniqueEmail(RegistrationForm):
"""
Subclass of ``RegistrationForm`` which enforces uniqueness of
email addresses.
"""
def clean_email(self):
"""
Validate that the supplied email address is unique for the
site.
"""
if User.objects.filter(email__iexact=self.cleaned_data['email']):
raise forms.ValidationError(validators.DUPLICATE_EMAIL)
return self.cleaned_data['email']
I want to implement a form that checks if the password has a number and a special character, but I'm failing to get the password? I'm not sure if it's even possible, but here is what I tried to get the password:
self.cleaned_data['id_password2']
self.cleaned_data['password2']
self.cleaned_data['password']
self.cleaned_data.get('id_password2')
self.cleaned_data.get('password2')
self.cleaned_data.get('password')
all of these return a NoneType object.
I also tried to define a clean_password2 function, but no help. Is this doable? And how so?
Thanks for any help,
Cleaned data isn't an attribute when you create a form, it is added when you call is_valid() on a form.
is_valid() will check that the data conforms to the constraint you put on it when creating the form (in this case, matching passwords and unique email by default for a RegistrationFormUniqueEmail). It might make sense to overwrite the is_valid() or create another function that calls is_valid() in addition to performing additional checks on password strength, instead of performing additional validation outside of the standard procedure
def custom_is_valid(self):
valid = self.is_valid()
if password.is.not.secure():
self.add_error('password', ValidationError(('Insecure Password'), code='invalid'))
valid = False
return valid
The above snipped might do the trick. The string 'password' in adding the error tacks it onto the form field you indicate, you may want to use password1 or password2 because I think that's the field name for the build in form you're using. Also, you wouldn't use cleaned_data to check password validity. You would just use the data attribute, form.data['password']
Related
I want to create a serializer that let users to login with their username or phone number,
Now if they use a phone number or username I need different validations.
I know that I can achieve this in the view, however, I'm looking for a solution to handle this situation in the serializer.
In the DRF the validate method can be used for example with the following code:
if '#' in data['value']:
# the validation for email should be done here
validator = EmailValidator()
validator(data['value'])
return data
else:
# here the mobile number should be validated
pass
I'm not sure what is the best/pythonic way of having a User document that automatically hashes its password upon creating.
Consider the following mongoengine model :
class User(Document):
email = EmailField(required=True, primary_key=True)
name = StringField(required=True)
pswd = StringField(required=True)
def check_pswd(self, password):
return verify_password(password, self.pswd)
def hash_pswd(self, password):
return hash_password(password):
def save(self, *args, **kwargs):
self.pswd = self.hash_pswd(self.pswd)
super().save(*args, **kwargs)
When I create a user, it works fine :
user = User()
user.email = 'user#email.com'
user.pswd = 'password'
user.name = 'User'
user.save()
Buf if I update it, it will double hash its password, I don't want that.
#User wants to change his name
user = User.objects(email='user#email.com')
user.name = 'User 2'
user.save()
Is there a way for me to hash its password only when creating or changing the password?
Or maybe I should delegate the responsibility of hashing the password to the View/Controller?
I am not giving you the code sample, you can use Document.update() method which will update the fields that only has changed.
If you still wanna use the save method,
Then you can create a logic along the following lines.
Check if the user has changed the password(by comparing the existing stored hash and new hash if any)
If the new hash is different then user has changed the password in that case you can push an Document.update method.
If not, don't call update on that field.
Alternatively update in Mongoengine accepts a iterable, so you can simply create a list or a dictionary object and convinently choose to Remove the password hash field from it.
As for who should execute this i.e View / Controller, its a Design decision but I would rather keep Representation (GUI / Front End) seperate from logic, so I would delegate this to the controller or even more Intrinsically to the Object who is responsible for handling all database/network related tasks, this way it would be isolated and easy to modify. And would not complexify or slow the View objects process / thread
Link for update using an iterable like Dict.
stackoverflow question for Mongoengine update using iterable
Link discussing save methods deprecation (The Maintainer Has commented below as save method not being deprecated, so trust him/her and proceed at will on this link)
Mongoengine save method deprecated?
Link for update method in mongoengine.
Mongoengine Atomic Update
Here is my signup form,
class SignupForm(forms.ModelForm):
class Meta:
model = User
fields = ['first_name', 'last_name','username', 'email', 'password']
def clean_username(self):
username = self.cleaned_data.get('username')
email = self.cleaned_data.get('email')
if username and User.objects.filter(username=username).exclude(email=email).count():
raise forms.ValidationError('This username has already been taken!')
return username
This works well to check if there is same username presents or not. However it does not check for case insensitivity. If there is a username e.g. 'userone', then it also accepts a username with 'Userone'. Although it does not break any functionality, but looks very unprofessional.
My question is how can I check for case insensitive right in the forms, and raise error?
Sometimes I faced the same issue. Django considers username unique different in lower or upper case. Like if I enter John, it a unique username and if I enter john, it's a new username. I need to consider John and john not in the database. As simple as facebook do, both uppercase and lower case username name is same, unique.
So I achieve this just changing my signup code like this.
username = self.cleaned_data.get('username').lower()
Also, in my login code, I convert my username to lower.
So that, all time it saves username lower in the database and log in with lower case username. Although a user tries to login with upper case username, then it saves to the database by converting to lower case.
You can use __iexact here:
User.objects.filter(username__iexact=username).exclude(email=email).exists() # instead of count, used exists() which does not make any DB query
Simplest method I think is:
Use .exists() method, if true then validation error else return ❤
Deform allows to add validation on different fields of a form. However, it checks that the form is valid in itself but that does not necessarily mean that the form processing will be valid.
For example, if the form is for creating a new user with an email address. The form is valid but the form processing (which consists in inserting this new user in a database) rises up a database integrity error saying there is already a user with this email address.
I know I could add a special validator that checks the email is not already used but still, there could be another concurrent transaction with the same email that commits between the check and the commit of the first transaction, which is not 100% safe at the end.
So, how can I nicely report form post-processing errors to the user?
I could easily report the error messages next to the form (flash message or other) but I would like to know if there is a way to report the error directly in the widgets exactly like normal validation errors are handled.
I faced the same situation and this how i achieve to raise the error as normal validation error.
Validator method:
def user_DoesExist(node,appstruct):
if DBSession.query(User).filter_by(username=appstruct['username']).count() > 0:
raise colander.Invalid(node, 'Username already exist.!!')
Schema:
class UserSchema(CSRFSchema):
username = colander.SchemaNode(colander.String(),
description="Extension of the user")
name = colander.SchemaNode(colander.String(),
description='Full name')
extension = colander.SchemaNode(colander.String(),
description='Extension')
pin = colander.SchemaNode(colander.String(),
description='PIN')
View:
#view_config(route_name='add_user', permission='admin', renderer='add_user.mako')
def add_user(self):
schema = UserSchema(validator = user_DoesExist).bind(request=self.request)
form = deform.Form(schema, action=self.request.route_url('add_user'), buttons=('Add User','Cancel'))
if 'Cancel' in self.request.params:
return HTTPFound(location = self.request.route_url('home'))
if 'Add_User' in self.request.params:
appstruct = None
try:
appstruct = form.validate(self.request.POST.items())
except deform.ValidationFailure, e:
log.exception('in form validated')
return {'form':e.render()}
Hope this will help you.
Thanks.
I'm trying to make a form that handles the checking of a domain: the form should fail based on a variable that was set earlier in another form.
Basically, when a user wants to create a new domain, this form should fail if the entered domain exists.
When a user wants to move a domain, this form should fail if the entered domain doesn't exist.
I've tried making it dynamic overload the initbut couldn't see a way to get my passed variabele to the clean function.
I've read that this dynamic validation can be accomplished using a factory method, but maybe someone can help me on my way with this?
Here's a simplified version of the form so far:
#OrderFormStep1 presents the user with a choice: create or move domain
class OrderFormStep2(forms.Form):
domain = forms.CharField()
extension = forms.CharField()
def clean(self):
cleaned_data = self.cleaned_data
domain = cleaned_data.get("domain")
extension = cleaned_data.get("extension")
if domain and extension:
code = whoislookup(domain+extension);
#Raise error based on result from OrderFormStep1
#raise forms.ValidationError('error, domain already exists')
#raise forms.ValidationError('error, domain does not exist')
return cleaned_data
Overriding the __init__ is the way to go. In that method, you can simply set your value to an instance variable.
def __init__(self, *args, **kwargs):
self.myvalue = kwargs.pop('myvalue')
super(MyForm, self).__init__(*args, **kwargs)
Now self.myvalue is available in any form method.
Do you have a model that stores the domains? If so, you want to use a ModelForm and set unique=True on whichever field stores the actual domain in the model. As of Django 1.2, you can even do any additional validation inside the model, rather than the form.