6. Data Validation with Pydantic | Custom Validators


In the previous article, we reviewed some of the common scenarios of Pydantic that we need in FastAPI applications. In this one, we will have a look into, How to validate the request data. As discussed earlier, We can not trust user-given data, so we need to preprocess them.

Let's take a very simple example, say we don't want the title to be less than 5 characters in length. This can be done as follow:

from pydantic import BaseModel, Field

class Blog(BaseModel):
    title: str = Field(...,min_length=5)
    is_active: bool

Blog(title="hi",is_active=False)
# Output: ValidationError: 1 validation error for Blog title
# ensure this value has at least 5 characters

min_length is just one of the available hooks, To know of more of the hooks see hooks for str, hooks for int, hooks for list. There are many more hooks e.g.

  • gt: int = None: enforces integer to be greater than the set value
  • multiple_of: int = None: enforces integer to be a multiple of the set value
  • strip_whitespace: bool = False: removes leading and trailing whitespace
  • regex: str = None: regex to validate the string against

Validation with Custom Hooks
In real-world projects and products, these validations are rarely sufficient. Say, we want to validate the title. If the title contains 'delete from' substring, We want to raise a ValueError. We can achieve this as follow:

from pydantic import BaseModel,Field, validator

class Blog(BaseModel):
    title: str = Field(...,min_length=5)
    is_active: bool

    @validator("title")
    def validate_no_sql_injection(cls, value):
        if "delete from" in value:
            raise ValueError("Our terms strictly prohobit SQLInjection Attacks")
        return value

Blog(title="delete from",is_active=True)
# Output: ValidationError: 1 validation error for Blog title
# Our terms strictly prohobit SQLInjection Attacks

In the above class Blog, We made a static class method, this takes in the value to validate. We do our checks and raise an Error if we find some issue. If everything looks well, we have to return a value that will be assigned to that property. We can even alter the value if required.

Validating interdependent properties with custom hooks
Many times, one property is dependent on another property of the class. I would like to quote a very beautiful example from pydantic docs. Say, we require the users to send their email, password, and confirm_password for registration. It is evident that we need to check if the password has the same value as that of confirm_password. In such cases, single field validation will not suffice. Pydantic provides a root_validator decorator which helps to tackle such cases.

from pydantic import BaseModel, root_validator

class CreateUser(BaseModel):
    email : str
    password :str 
    confirm_password :str 

    @root_validator()
    def verify_password_match(cls,values):
        password = values.get("password")
        confirm_password = values.get("confirm_password")

        if password != confirm_password:
            raise ValueError("The two passwords did not match.")
        return values

CreateUser(email="[email protected]",password="1234",confirm_password="123")

# Output: ValidationError: 1 validation error for CreateUser __root__
#  The two passwords did not match. (type=value_error)

There are many more features, however, these are the most common and useful patterns for FastAPI. We will look into some more features in the course itself.

FastAPITutorial

Brige the gap between Tutorial hell and Industry. We want to bring in the culture of Clean Code, Test Driven Development.

We know, we might make it hard for you but definitely worth the efforts.

Contacts

Refunds:

Refund Policy
Social

Follow us on our social media channels to stay updated.

© Copyright 2022-23 Team FastAPITutorial