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.'
Related
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',......)
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.
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.
I am using a text box to get the mobile number from the user.
models.py
mobile = models.CharField(max_length=14, validators=[MinLengthValidator(10)])
The default error message looks like:
Ensure this value has at least 10 characters (it has 2).
How can I override the error message?
Django has added a message parameter, so in the future you'll be able to say validators=[MinLengthValidator(10, message='My message')].
For now, the simplest thing is probably just to instantiate the class and set the message attribute.
my_validator = MinLengthValidator(10)
my_validator.message = 'My message'
If you don't like relying on undocumented code, then just write the validator yourself, it will only be a few lines.
Yes by removing the validator and writing your own. You can do this by overriding your form's clean method.
def clean(self):
cleaned_data = super(YourForm, self).clean()
mobile = cleaned_data.get("mobile")
if len(mobile) < 10:
raise forms.ValidationError("Your message here.")
I have an extended UserProfile for registering new users. My user_created function connects to signals sent upon registering basic User instance and creates new UserProfile with extended fields from my form. Here's the code :
from registration.signals import user_registered
from accounts.forms import ExtendedRegistrationForm
import accounts
from accounts.models import UserProfile
def user_created(sender, user, request, **kwargs):
form = ExtendedRegistrationForm(request.POST, request.FILES)
data = UserProfile(user=user)
data.is_active = False
data.first_name = form.data['first_name']
data.last_name = form.data['last_name']
data.pid = form.data['pid']
data.image = form.data['image']
data.street = form.data['street']
data.number = form.data['number']
data.code = form.data['code']
data.city = form.data['city']
data.save()
user_registered.connect(user_created)
Problem is that on this form I have an image field for avatar. As you can see from the code, I'm getting data from form's data list. But apparently imageField does not send it's data with POST request(as I'm getting MultiValueDictKeyError at /user/register/, Key 'image' not found in <QueryDict...) so I can't get it from data[] .
alt text http://img38.imageshack.us/img38/3839/61289917.png
If the usual variables are inside 'data', where should I look for files ? Or is the problem more complicated ? Strange thing is that my form doesn't have attribute cleaned_data... I was using dmitko's method here : http://dmitko.ru/?p=546&lang=en . My :
forms : http://paste.pocoo.org/show/230754/
models : http://paste.pocoo.org/show/230755/
You should be validating the form before using it, which will create the "cleaned_data" attribute you're used to. Just check form.is_valid() and the "cleaned_data" attribute will be available, and should contain the file.
The form's "data" attribute is going to be whatever you passed in as its first initalization argument (in this case, request.POST), and files are stored separately in the "files" attribute (whatever you pass in as the second argument, in this case, request.FILES). You don't want to be accessing the form's "data" or "files" attributes directly, as, if you do, you're just reading data straight from the request and not getting any benefit from using forms.
Are you sure the <form enctype="..."> attribute is set to multipart/form-data ? Otherwise the browser is not able to upload the file data.