Django form warning messages - django

My Django form asks for a specific number (1345 in this case). Yet if the user types in some other number a warning message appears indicating the upper/lower bound of the allowed integer. How do I prevent these specific warning messages? The response to a false input should always be: "Wrong." What is the easiest way to achieve this behavious?
#models.py
class Player():
code = models.PositiveIntegerField(min=1345,max=1345)
#etc
#template.html
{% formfield player.code with label="What is the code?" %}

You can display error_messages
from django.utils.translation import gettext_lazy as _
class PlayerForm(ModelForm):
class Meta:
model = Player
fields = "__all__"
error_messages = {
'code': {
'max_value': _("You have to enter below the 1345."),
'min_value': _("You have to enter above the 1345."),
}
}
So now you should get the idea. Just put text whatever you wish.

Related

How to change serializer field name when validation error is triggered

I need to change the view of the error displayed when I validate the field.
serializer.py
class ElementCommonInfoSerializer(serializers.ModelSerializer):
self_description = serializers.CharField(required=False, allow_null=True,
validators=[RegexValidator(regex=r'^[a-zA-Z0-9,.!? -/*()]*$',
message='The system detected that the data is not in English. '
'Please correct the error and try again.')]
)
....
class Meta:
model = Elements
fields = ('self_description',......)
This error is displayed
{
"self_description": [
"The system detected that the data is not in English. Please correct the error and try again."
]
}
The key of error dict is field name - self_description. For FE I need to send another format like:
{
"general_errors": [
"The system detected that the data is not in English. Please correct the error and try again."
]
}
How to change this?
One way this could be achieved is via custom exception handler
from copy import deepcopy
from rest_framework.views import exception_handler
def genelalizing_exception_handler(exc, context):
# Call REST framework's default exception handler first,
# to get the standard error response.
response = exception_handler(exc, context)
# Now add the HTTP status code to the response.
if 'self_description' in response.data:
data = deepcopy(response.data)
general_errors = data.pop('self_description')
data['general_errors'] = general_errors
response.data = data
return response
in settings
REST_FRAMEWORK = {
'EXCEPTION_HANDLER': 'my_project.my_app.utils. genelalizing_exception_handler'
}
Another solution is to rewrite the validate method.
def validate(self, data):
self_description = str((data['self_description']))
analyst_notes = str((data['analyst_notes']))
if re.match(r'^[a-zA-Z0-9,.!? -/*()]*$', self_description) or re.match(r'^[a-zA-Z0-9,.!? -/*()]*$', analyst_notes):
raise serializers.ValidationError({
"general_errors": [
"The system detected that the data is not in English. Please correct the error and try again."
]
})
return data
The solution is very simple.
you can rename the key field by using serializer method (source attribute)
below you can find an example code.
class QuestionSerializer(serializers.ModelSerializer):
question_importance = serializers.IntegerField(source='importance')
question_importance = serializers.IntegerField(required=False)
class Meta:
model = create_question
fields = ('id','question_importance','complexity','active')
Above you can see I have an importance field which is present in django model But here I renamed this field to question_importance by using source attribute .
In your case it will be like below,
class ElementCommonInfoSerializer(serializers.ModelSerializer):
general_errors = serializer.CharField(source="self_description")
general_error = serializers.CharField(required=False, allow_null=True,
validators=[])
class Meta:
model = Elements
fields = ('general_error',......)

Validation not running in django form

I want to run field validatin on my form, as in form and field validation- using validation in practice.
My form looks like this:
from kapsule.validators import name_zero_min_length, name_max_length
class NameUpdateForm(forms.Form):
name = forms.CharField(
validators=[
name_zero_min_length,
name_max_length
]
)
My validators:
from django.core.exceptions import ValidationError
def name_zero_min_length(name_field):
# Check minimum length
if not len(name_field) > 0:
print('firing zero length')
raise ValidationError(
"My custom error message name must be at least one character"
)
def name_max_length(name_field):
# Check that the name is under the max length
MAX_LENGTH = 200
if len(name_field) > MAX_LENGTH:
print('raising')
raise ValidationError(
"My custom error message name cannot be more than {} characters".format(MAX_LENGTH)
)
My view like this:
def edit_kapsule_name(request, kapsule_pk):
kapsule = Kapsule.objects.get(pk=kapsule_pk)
form = NameUpdateForm(request.POST)
response = {}
print('pre-validation')
if form.is_valid():
print('VALID')
name = form.data.get('name')
kapsule.name = name
kapsule.save(update_fields=['name'])
else:
print('INVALID') # INVALID
print('json') # json
errors = form._errors.as_json()
print(errors) # {"name": [{"message": "This field is required.", "code": "required"}]}
My output is commented in the above code (invalid, and giving a different error that that which I expected).
Why is my custom validation not running?
This seems to match with my model validation (working), and the second reponse here
Well in the comment from your code I can see that the form is invalid and it is complaining about a required field. That might be the cause your validators are not running, according to the docs:
The clean() method on a Field subclass is responsible for running to_python(), validate(), and run_validators() in the correct order and propagating their errors. If, at any time, any of the methods raise ValidationError, the validation stops and that error is raised. This method returns the clean data, which is then inserted into the cleaned_data dictionary of the form.
On the other hand, if the field is required, the validation not len(name_field) > 0 has no much sense.
Try calling your validators as part of the clean_name method in your form.

Django form "soft" validation, send back to user for explicit confirmation of doubtful data

I have an integer field in a form that must be in the range 100 to 1000. However, if a value other than 100, 200, 381 (don't ask), 525 or 1000 is entered, it is quite probable that this is erroneous.
What I'd like to do is what I'm calling "soft validation" -- I don't know if there is any standard terminology. The first time, the form would raise errors and then "Confirm?" boolean field(s) would be added, default false. If it comes back again with the confirm field(s) true, then unlikely data will be accepted.
The answer Warnings (or even info messages) instead of only errors in Django shows how to accomplish this with custom code added field-by-field and form-by-form -- but I'd rather not do it this way. Does anybody know whether this has already been done in open-source code in a generalized, re-usable way? In my dreams, I would raise ValidationWarning ... (which doesn't exist) and the rest would look after itself.
I don't know what to search for with Google. I can't find anything obvious at https://djangopackages.org/
Here you find a minimal working example similar to the one given in the link in the comment. You only have to be carefully to not include the soft validation in the clean_MagicNumber(self) function - this is prone to race conditions because the clean_data attributes are only set.
Instead use the overwritten clean(self) or validate_unique(self) function.
from django.core.exceptions import ValidationError
from django.db import models
from django.contrib import admin
from django import forms
from django.db import models
class Autor(models.Model):
Name = models.CharField(max_length=64)
MagicNumber = models.IntegerField()
class AutorAdminForm(forms.ModelForm):
ConfirmMagicNumber = forms.BooleanField(label="I confirm it is the right magic number.",
required=False,
widget=forms.HiddenInput)
def _field_is_active(self, field):
if self._meta.exclude is not None and field in self._meta.exclude:
return False
if self._meta.fields is not None and field in self._meta.fields:
return True
return False
def clean_MagicNumber(self):
if self.cleaned_data['MagicNumber'] < 100 or self.cleaned_data['MagicNumber'] > 1000:
raise ValidationError("Magic number outside of allowed range between 100 to 1000.")
return self.cleaned_data['MagicNumber']
def validate_unique(self):
"""
We use validate unique because it is quite late in the validation process,
after we got the values of all fields and
actually I used it, because I was really warning for a possible duplicate
"""
super().validate_unique()
# only check if number does not have errors and is in form data
if 'MagicNumber' not in self._errors and 'MagicNumber':
# only check if confirm checkbox is given and not checked
if ('ConfirmMagicNumber' in self.cleaned_data and 'ConfirmMagicNumber' in self.fields
and self.cleaned_data['ConfirmMagicNumber'] is not True and self._field_is_active('ConfirmMagicNumber')):
if self.cleaned_data['MagicNumber'] not in (100, 200, 381, 525, 1000):
error_msg = "The magic number looks wrong. Please confirm it below."
self.add_error('MagicNumber', error_msg)
self.fields['ConfirmMagicNumber'].widget = forms.CheckboxInput()
self.fields['ConfirmMagicNumber'].required = True
#admin.register(Autor)
class AutorAdmin(admin.ModelAdmin):
form = AutorAdminForm

How to extract Django Form errors message without the HTML tags

I need to extract the messages and field.
For Example, I have this django form error result
<ul class="errorlist">
<li>__all__
<ul class="errorlist nonfield">
<li>Pointofsale with this Official receipt and Company already exists.</li>
</ul>
</li>
</ul>
from the output of this code
def post_sale(request):
sale_form = request["data"]
if sale_form.is_valid():
save_form.save()
else:
print save_form.errors
But what i need to achieve is to get the message without the tags, so i could just return those message in plain string/text.
def post_sale(request):
sale_form = request["data"]
if sale_form.is_valid():
save_form.save()
else:
# This is just pseudo code
for field in save_form.errors:
field = str(field["field"})
message = str(field["error_message"])
print "Sale Error Detail"
print field
print message
error_message = { 'field':field,'message':message }
error_messages.append(error_message )
The output would be:
Sale Error Detail
(the field where form error exists)
Pointofsale with this Official receipt and Company already exists.
Explored Questions and Documentations
displaying django form error messages instead of just the field name
Getting a list of errors in a Django form
django form errors. get the error without any html tags
How do I display the Django '__all__' form errors in the template?
https://docs.djangoproject.com/en/1.10/ref/forms/api/
https://docs.djangoproject.com/en/1.10/topics/forms/
Thanks, please tell if something is amiss or something needs clarification so i could fix it.
The errors property of a bound form will contain all errors raised by that form, as a dictionary. The key is a field or other special values (such as __all__), and the value is a list of one or more errors.
Here is a simple example on how this works:
>>> from django import forms
>>> class MyForm(forms.Form):
... name = forms.CharField()
... email = forms.EmailField()
...
>>> f = MyForm() # Note, this is an unbound form
>>> f.is_valid()
False
>>> f.errors # No errors
{}
>>> f = MyForm({}) # Now, the form is bound (to an empty dictionary)
>>> f.is_valid()
False
>>> f.errors # dictionary of errors
{'name': [u'This field is required.'], 'email': [u'This field is required.']}
In your view, depending on what you want you can just return the value of form.errors, or parse it to whatever structure your need.
for field, errors in form.errors.items():
print('Field: {} Errors: {}'.format(field, ','.join(errors))
For the specific error you have mentioned, it is a custom error raised as a result of overriding the clean() method - which is why it is listed under the special identifier __all__ and not under a specific field.
This is mentioned in the forms reference, under validation:
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__), which you can access via the
non_field_errors() method if you need to. If you want to attach errors
to a specific field in the form, you need to call add_error().

Django - Change the max_length error message on a CharField TextInput

I am trying to customize the error message displayed when a user inputs text longer than the max length for a CharField in my model. The model defines the field as follows:
name = models.CharField(max_length=200)
I have a ModelForm for this model that defines the form field as follows:
name = forms.CharField(widget=forms.TextInput(attrs={'class':"span8", 'placeholder':'e.g. How do I setup a wi-fi network? How to sync my iPhone with iCloud?'}),
error_messages={'required': 'Please enter a question.', 'max_length': 'Your question is too long.'})
This works fine for the 'required' error message, but the 'max_length' error message still uses Django's default message here. Am I doing something wrong or should this text be customized in some other way?
The 'max_length' is checked by 'django.core.validators.MaxLengthValidator', which has hard-coded error message. You could replace it w/ your own version by:
# after the name or ModelForm definition
name.validators[-1].message = 'Your question is too long.'
I'm not sure from which version it is working, but now you can do this:
class YouForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
self.fields['you_field'].error_messages = {'max_length': 'Ensure this value has at most %(limit_value)d character (it has %(show_value)d).'}
You can create subclass of 'django.core.validators.MaxLengthValidator'
from django.core.validators import MaxValueValidator
class MyValidator(MaxValueValidator):
message = 'Your question is too long.'