Validation
Liveblade provides a flexible and intuitive validation system that can be used to validate both individual properties and entire forms.
Here’s an example PostCreate
component that demonstrates the most basic validation workflow in Liveblade:
from pyblade import liveblade
from app.models import Post
class PostCreate(liveblade.Component):
title: str = ""
content: str = ""
def save(self):
validated = self.validate({
'title': 'required|string|min:3',
'content': 'required|string|max:5000',
})
Post.objects.create(**validated)
return self.redirect('/posts')
def render(self):
return self.view('liveblade.create-post')
As you can see, Liveblade provides a validate()
method you can call inside any component action to validate the component’s state. It returns the validated data, which you can safely use — for example, to create a database record.
On the frontend, validation errors are displayed using existing PyBlade directives like @error
.
<form b-submit="save">
<input type="text" b-model="title">
<div>@error('title') {{ message }} @enderror</div>
<textarea b-model="content"></textarea>
<div>@error('content') {{ message }} @enderror</div>
<button type="submit">Save</button>
</form>
Property-Based validation with @validators
If you prefer to keep your validation rules close to the properties they apply to, Liveblade offers a convenient @validators
decorator.
By attaching validation rules directly to component properties using @validators
, Liveblade will automatically validate those properties whenever they are updated. This is especially useful for real-time validation and cleaner component logic.
However, when you're about to persist data (e.g., saving to a database), it's important to still call self.validate()
manually. This ensures that all properties are validated — including those that haven't changed during the current interaction.
from pyblade import liveblade
from app.models import Post
class PostCreate(liveblade.Component):
@property
@validators("required|string|min:3")
def title(self): pass
@property
@validators("required|string|max:5000")
def content(self): pass
def save(self):
self.validate()
Post.objects.create(title=self.title, content=self.content)
return self.redirect('/posts')
def render(self):
return self.view('liveblade.create-post')
NOTE
Validation rules may be a list of strings, or a string of |
(pipe) separated values.
Pro Tip !
You can omit the @property
decorator. When using @validators
, Liveblade automatically treats the method as a property for you.
Disabling auto-validation
If you want full control over when validation happens, you can disable the automatic validation behavior by setting on_update=False
in the @validators
decorator. This tells Liveblade not to validate the property on every update—you’ll handle validation manually instead, typically using self.validate()
in your action methods:
from pyblade import liveblade
from app.models import Post
class PostCreate(liveblade.Component):
@validators("required|string|min:3", on_update=False)
def title(self): pass
@validators("required|string|max:5000", on_update=False)
def content(self): pass
def save(self):
validated = self.validate()
Post.objects.create(**validated)
return self.redirect('/posts')
This approach is useful when you only want to validate inputs at specific points in the workflow, such as right before form submission or a save operation.
Disabling Localization
By default, PyBlade will localize validation messages using your framework's translation system, if available, else, PyBlade translation system will be used.
To disable automatic translation and keep messages exactly as defined, set translate=False
in the decorator:
class PostCreate(liveblade.Component):
@validators("required", message="Please provide a post title", translate=False)
def title(self): pass
This ensures the validation message is displayed exactly as written, without being passed through a translation layer.
Customizing error messages
Out-of-the-box, PyBlade provides sensible validation messages like "The title field is required." if the title
property has the required
rule attached to it.
However, you may need to customize the language of these error messages to better suite your application and its users.
Custom property names
Sometimes the property you are validating has a name that isn't suited for displaying to users. For example, if you have a database field in your app named dob
that stands for "Date of birth", you would want to show your users "The date of birth field is required" instead of "The dob field is required".
Liveblade allows you to specify an alternative name for a property using the aslias
parameter in @validators
decorator :
@validators('required', alias='date of birth')
def dob(self): pass
Now, if the validation fails, PyBlade will use "date of birth" instead of "dob" in the error message. So instead of saying "The dob field is required", the message will read: "The date of birth field is required".
Custom validation messages
Sometimes, customizing the property name isn't enough. You may need to customize the entire validation message. To override the default validation message provided by PyBlade, you can use the message
parameter inside the @validators
decorator:
class PostCreate(liveblade.Component):
@validators("required", message="Please provide a post title")
def title(self): pass
Now, if validation fails, the message will be: "Please provide a post title" instead of the default "The title field is required".
You can also define different messages for different rules by passing a diactionnary to the message
parametter :
class PostCreate(liveblade.Component):
@validators("required|min", message={"required": "Please provide a post title", "min": "This title is too short"})
def title(self): pass
In this case:
- If the field is empty, the message will be "Please provide a post title"
- If it's too short, it will show: "This title is too short"
Defining a validators()
method
As an alternative to Liveblade's @validators
decorator, you can define a method in your component called validators()
and return a list of fields and corresponding validation rules.
These rules will then be applied when you run self.validate()
inside the component. You also can define the validation_attributes
and messages()
functions.
Here's an example:
from pyblade import livablade
from app.models import Post
class PostCreate(liveblade.Component):
def validators(self):
return {
'title' => "required|min:3",
'content' => 'required|min:20|max:5000',
}
def messages(self):
return {
'content.required': 'The content are missing.',
'content.min': 'The content is too short.',
}
def validation_attributes(self):
return {'dob' => 'date of birth'}
def save(self)
self.validate()
Post.objects.create(title=self.title, content=self.content)
The `validators()` method doesn't validate on data updates
When defining rules via the validators()
method, Liveblade will ONLY use these validation rules to validate properties when you run self.validate()
. This is different than standard @validators
decorators which are applied every time a field is updated via something like b-model
. To apply these validation rules to a property every time it's updated, you can still use @validators
with no extra parameters.
Don't conflict with Liveblade's mechanisms
While using Liveblade's validation utilities, your component should not have properties or methods named validators
, messages
or validation_attributes
, unless you're customizing the validation process. Otherwise, those will conflict with Liveblade's mechanisms.
Form classes
As more properties and validation rules are added to a Liveblade component, it can begin to feel too crowded. To alleviate this pain and also provide a helpful abstraction for code reuse, Liveblade offers Form classes, inspired by Django-style forms. These are especially useful for Python web frameworks that don’t offer form validation features out of the box.
Below is the same PostCreate
example, but now the properties and rules have been extracted to a dedicated form class named PostForm
:
# livablade/forms.py
from pyblade import forms
class PostForm(forms.Form):
title = forms.CharField(required=True, min_lenght=3)
content = forms.TextField(required=True,max_length=5000)
The PostForm
above can now be defined as a property on the CreatePost
component:
from pyblade import liveblade
from .forms import PostForm
class PostCreate(liveblade.Component):
form: PostForm
def save(self):
if self.form.is_valid():
Post.objects.create(**self.form.validated)
return redirect('/posts')
...
As you can see, instead of listing out each property individually, we can retrieve all the property values using the .validated
attribute on the form class.
Also, when referencing the property names in the template, you must prepend form.
to each instance:
<form b-submit="save">
<input type="text" b-model="form.title">
<div>@error('form.title') {{ message }} @enderror</div>
<textarea b-model="form.content"></textarea>
<div>@error("form.content") {{ message }} @enderror</div>
<button type="submit">Save</button>
</form>
Form classes are a useful abstraction for most larger datasets and a variety of additional features that make them even more powerful. For more information, check out the comprehensive form objects documentation.