How to make form validation in Django dynamic? - python

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.

Related

Where is this self.add_error adds the error to?

I'm having a hard time trying to figure out the following code:
from django import forms
from django.contrib.auth.hashers import check_password
class CheckPasswordForm(forms.Form):
password = forms.CharField(label='password_check', widget=forms.PasswordInput(
attrs={'class': 'form-control',}),
)
def __init__(self, user, *args, **kwargs):
super().__init__(*args, **kwargs)
self.user = user
def clean(self):
cleaned_data = super().clean()
password = cleaned_data.get('password')
confirm_password = self.user.password
if password:
if not check_password(password, confirm_password):
self.add_error('password', 'password is wrong')
here, I don't get the self.add_error('password', 'password is wrong') part. In the documentation, it says that the password here is the field in add_error('field', 'error').
So, is the error being added to the password field? or is it being added to the following part?
def __init__(self, user, *args, **kwargs):
super().__init__(*args, **kwargs)
self.user = user
because if I have to access this error in the html template, I would have to do something like this,
{% if password_form.password.errors %}
and if it means accessing errors from password field, it should mean that the error is added to the password field... but the self.add_error part confuses me
Form clean method is responsible for validation of your form when the data is sent to it
normally it will run validation on all field using clean_<fieldname>() method and if there are errors store them in fieldname.errors
As documented
Since the field validation methods have been run by the time clean()
is called, you also have access to the form’s errors attribute which
contains all the errors raised by cleaning of individual fields.
Note that any errors raised by your Form.clean() override will not be
associated with any field in particular. They go into a special
“field” (called __all__)
if you don't want error to end into __all__ you can attach it to particular field in your case you added it to password
If you want to attach errors to a specific field in the form, you
need to call add_error().

MongoEngine - Call function only when document is being created or specific field being set?

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

How can I disable the wtforms SelectField choices validation?

I have a wtforms form
class MyForm(Form):
names = SelectField('name', choices=[])
The choices of names field is built dynamically and rendered in the template by an ajax call. When I submit the form, it raises an exception "not a valid choice". I don't want the form to validate the choices of names field for me. How can I disable the validation?
I did something like this to step around the SelectMultipleField validation in WTForms. It should work the same way with a plain SelectField
class NonValidatingSelectMultipleField(SelectMultipleField):
"""
Attempt to make an open ended select multiple field that can accept dynamic
choices added by the browser.
"""
def pre_validate(self, form):
pass
I simply override the built-in validation.
I was stuck with the same issue. The solution provided by Xealot is great. I found that there is an option to set validation to False using validate_choice=False. I have included an example of both the solutions below.
class NonValidatingSelectField(SelectField):
"""
Attempt to make an open ended select multiple field that can accept dynamic
choices added by the browser.
"""
def pre_validate(self, form):
pass
class MyForm(Form):
names = NonValidatingSelectField('name')
names2 = SelectField('name2', validate_choice=False)
By "I don't want the form to validate the choices", I assume you actually mean "I'm going to do it myself later and doubt the form's ability to do it correctly".
But you are in luck! You can subclass an existing form to add choices dynamically.
class MyForm(Form):
# other fields...
def some_handler(request):
name_choices = build_name_choices()
class RealForm(MyForm):
names = SelectField('name', choices=name_choices)
form = RealForm(request.GET)
form.validate()
This also saves you from the tedium of merging the form's validation and error messages with those you generate yourself later.

Django Tastypie, do stuff after creating a user

I'd like to add some values to my user Profile model after I create (POST) a user with Tastypie.
This is just one scenario, I have other instances where I might want to alter the data PRE or POST save in my tastypie resource. Is this possible or how would I go about achieving this?
Thanks for your help.
Will a signal do what you want?
You can also override obj_create on your Tastypie user resource.
This will give you access to the bundle where the user object is and you can put more values to the fields there.
Here's an example:
def obj_create(self, bundle, request=None, **kwargs):
try:
username = bundle.data['username']
password = bundle.data['password']
bundle.obj = User.objects.create_user(username,password)
# add more stuff here
bundle.obj.save()
return bundle

Is there a way to pass extra fields to a form with WTForms?

I am writing a change password form, and I would like to pass the original password to the form for validation purposes, but the only way to do that is to make it a hidden field and pass it in with the rest of the data. I obviously don't want to do that, I'd rather just pass it to the form constructor from within the view, but if it's not passed in with the formdata then that won't work.
class MyForm(Form):
...
original_password = HiddenField()
...
def validate_current_password(form, field):
if field.data != form.original_password.data:
ERROR
form = MyForm(request.POST, original_password=password) Does not work unless request.POST is empty, or unless I actually render and submit the original password with the form. form.original_password.data is empty otherwise.
For those of you familiar with formencode's "state" variable, I solved this by subclassing Form and adding a state variable with information to assist in validation.

Categories

Resources