Django ModelForm float field not calling Clean_Field method - django

i am having a unique kind of problem.
i am putting "$90" value in my floatField.
i assume it should be cleaned and stored as "90.0" in the model.
but when i input "$90" and call clean_filed method, it does not call that clean method.
but when i apply the breakpoint on clean(self) mehthod and try to get its value, its says None.
please help me out. here is my code.
Model
class Project(models.Model):
foo = models.FloatField("foo",
null=True, blank=True
)
forms
widgets = {
'foo': forms.TextInput(attrs={'currency': 'true'})}
def clean_foo(self):
value = self.cleaned_data.get('foo')
print value # i get NONE here.............
return value

The clean_<field> hooks in the forms API are for doing additional validation. It is called after the field calls its clean method. If the field does not consider the input valid then the clean_<field> is not called. This is noted in the custom validation docs https://docs.djangoproject.com/en/stable/ref/forms/validation/
For any field, if the Field.clean() method raises a ValidationError, any field-specific cleaning method is not called. However, the cleaning methods for all remaining fields are still executed.
In your case because $90 does not validate as a float it will not be called. Instead what you should do is create a subclass of the FloatField which cleans the input (removing $, etc) prior to validating the input as a float.

Related

How clean_botcatcher(self): automatically called?

I got confused, does django automatically calls clean_botcatcher(self): . Does it acts as listener which got triggered when bot makes changes to values?
from django import forms
class FormName(forms.Form):
name = forms.CharField()
email = forms.EmailField()
text = forms.CharField(widget=forms.Textarea)
botcatcher = forms.CharField(required=False,widget =forms.HiddenInput)
def clean_botcatcher(self):
botcatcher = self.cleaned_data['botcatcher']
if len(botcatcher) > 0:
raise forms.ValidationError("Gotcha BOT")
return botcatcher
The clean_() method is called on a form subclass – where is replaced with the name of the form field attribute. This method does any cleaning that is specific to that particular attribute, unrelated to the type of field that it is. This method is not passed any parameters. You will need to look up the value of the field in self.cleaned_data and remember that it will be a Python object at this point, not the original string submitted in the form (it will be in cleaned_data because the general field clean() method, above, has already cleaned the data once).
For example, if you wanted to validate that the contents of a CharField called serialnumber was unique, clean_serialnumber() would be the right place to do this. You don’t need a specific field (it’s a CharField), but you want a formfield-specific piece of validation and, possibly, cleaning/normalizing the data.
The return value of this method replaces the existing value in cleaned_data, so it must be the field’s value from cleaned_data (even if this method didn’t change it) or a new cleaned value.
reference https://docs.djangoproject.com/en/4.0/ref/forms/validation/
I'm assuming you're going through Jose Portilla's course on udemy? Because I just went over this exact section. I believe the def function inside the class FormName runs automatically. He was saying that if the value in the form has been altered by the bot, then this function will catch the bot and give you the validation error.

django model form clean method with foreign key

I try override clean method for model form with foreign key.
Model:
class Doc(Model):
name = CharField()
doc_type = ForeignKey(DictDocType)
Form:
class DocForm(ModelForm):
class Meta:
model = Doc
fields = '__all__'
def clean_doc_type(self)
doc_type_name = self.cleaned_data['doc_type']
try:
DictDocType.objects.get(name=doc_type_name)
except DictDocType.DoesNotExist:
msg = '{0} does not exist in dictdoc {1}.'.format(
doc_type_name, self.cleaned_data['name'])
raise ValidationError(msg)
return name
In the test I get an error:
KeyError: 'name'.
If I remove self.cleaned_data['name'] from msg - I do not get self.cleaned_data['doc_type'].
Where I'm wrong?
You can't cross reference other fields in clean_foo methods, because not all fields' clean_foo methods are called when you are in one of them. There might be some values of the form that are not populated yet, so clean_name() is not yet called when you call clean_doc_type(), thus you don't have self.cleaned_data['name'].
This should be done in clean method. Django doc very explicitly documented this:
By the time the form’s clean() method is called, all the individual
field clean methods will have been run (the previous two sections), so
self.cleaned_data will be populated with any data that has survived so
far. So you also need to remember to allow for the fact that the
fields you are wanting to validate might not have survived the initial
individual field checks.
Also, your clean method doesn't make much sense and not necessary at all. You wouldn't able to choose a foreignkey that doesn't exist in ModelForm. Even if you force the front end to do so, the field would auto fail the validation and give error:
Select a valid choice. foo is not one of the available choices.

Django form field validation - How to tell if operation is insert or update?

I'm trying to do this in Django:
When saving an object in the Admin I want to save also another object of a different type based on one of the fields in my fist object.
In order to do this I must check if that second object already exists and return an validation error only for the particular field in the first object if it does.
My problem is that I want the validation error to appear in the field only if the operation is insert.
How do I display a validation error for a particular admin form field based on knowing if the operation is update or insert?
P.S. I know that for a model validation this is impossible since the validator only takes the value parameter, but I think it should be possible for form validation.
This ca be done by writing a clean_[name_of_field] method in a Django Admin Form. The insert or update operation can be checked by testing self.instance.pk.
class EntityAdminForm(forms.ModelForm):
def clean_field(self):
field = self.cleaned_data['field']
insert = self.instance.pk == None
if insert:
raise forms.ValidationError('Some error message!')
else:
pass
return field
class EntityAdmin(admin.ModelAdmin):
form = EntityAdminForm
You have to use then the EntityAdmin class when registering the Entity model with the Django admin:
admin.site.register(Entity, EntityAdmin)
You can write your custom validation at the model level:
#inside your class model ...
def clean(self):
is_insert = self.pk is None
from django.core.exceptions import ValidationError, NON_FIELD_ERRORS
#do your business rules
if is_insert:
...
if __some_condition__ :
raise ValidationError('Dups.')
Create a model form for your model. In the clean method, you can set errors for specific fields.
See the docs for cleaning and validating fields that depend on each other for more information.
That is (probably) not an exact answer, but i guess it might help.
Django Admin offers you to override save method with ModelAdmin.save_model method (doc is here)
Also Django api have a get_or_create method (Doc is here). It returns two values, first is the object and second one is a boolean value that represents whether object is created or not (updated an existing record).
Let me say you have FirstObject and SecondObject
In your related admin.py file:
class FirstObjectAdmin(admin.ModelAdmin):
...
...
def save_model(self, request, obj, form, change):
s_obj, s_created = SecondObject.objects.get_or_create(..., defaults={...})
if not s_created:
# second object already exists... We will raise validation error for our first object
...
For the rest, I do not have a clear idea about how to handle it. Since you have the form object at hand, you can call form.fields{'somefield'].validate(value) and write a custom validation for admin. You will probably override clean method and try to trigger a raise ValidationError from ModelAdmin.save_model method. you can call validate and pass a value from there...
You may dig django source to see how django handles this, and try to define some custom validaton steps.

Model validation. Don't want to repeat myself. Django

I have a model M that has a field num=models.IntegerField()
I have a modelform called F for model M.
I want to ensure that num is never negative.
If I do validation in my form class, F, then I can do clean_num():
if negative then throw ValidationError('Num can never be negative').
This ValidationError will be automatically redisplayed to the user by
redirecting him to back to the form that he submitted and displaying
the 'Num can never be negative' message on top of the num field.
Thats all done automatically by django as soon as I throw the
ValidationError from the clean_fieldname method.
I would like to be able to do all that, but in the model class.
F is the ModelForm created from a model class M. M defines that
the field num can never be negative.
When I'm calling is_valid() on a form, I want the functions defined in the model
to check for validation for any ModelForm that references this model.
How can I achieve this?
See Model validation (Django 1.2+ only).
You could also use PositiveIntegerField for this particular problem.
If your validation depends only on field value, you can implement your own field type as described here: https://docs.djangoproject.com/en/dev/howto/custom-model-fields/
Thanks to everyone who posted an answer. But i found exactly what i asked about so if you're interested:
You can define the proper validators just once for the model. All the forms using this model will have the ValidationError('cant use this name') be appended to their field_name.errors list.
Note, that they will be added to the field in the form for which the model field validator is running.
Anyway, check this out:
Django: how to cleanup form fields and avoid code duplication

Django ModelForm is_valid() error types

I have a EmailField(primary_key=True). I'm using a ModelForm to render a form to a user and on the post back I am calling form.is_valid().
I am seeing two types of errors on this field. One is a unique value constraint on the primary key (this email address already exists). The other is an invalid email address error.
I would like to respond differently to each error. Is there an easy way to identify that validation failure was due to an actual input format error vs a unique constraint?
I figured out how to achieve what I wanted. My goal was to avoid the unique constraint so that I could silently ignore the form submission and succeed (from the user perspective, since their submission was a noop) in the case of a duplicate email address being submitted.
First override the validate_unique method on my ModelForm definition.
from django.forms import ModelForm
from apps.announcer.models import Subscriber
class SubscribeForm(ModelForm):
class Meta:
model = Subscriber
exclude = ('created',)
def validate_unique(self):
pass
Because the validate_unique method has been converted to a noop the view will have to perform whatever validation it needs. So instead of calling form.save() call entity = form.save(commit=False). Perform the needed validation on entity and if needed call entity.save().
Could you check for a pre-existing key first, then call is_valid()?