2023-03-10

Inheriting Pydantic Models

Inheriting Pydantic Models

Inheritance is a fundamental concept in object-oriented programming that allows developers to create new classes based on existing ones, reusing and extending functionality. In this chapter, I will explore how to inherit Pydantic models to create more efficient and maintainable code.

Creating a Base Model

To start, we need to create a base model that serves as the foundation for our inherited models. In Pydantic, a model is defined using the BaseModel class. Let's create a simple example:

python
from pydantic import BaseModel, EmailStr

class User(BaseModel):
    id: int
    name: str
    email: EmailStr

Extending the Base Model

Now that we have our base User model, we can create a new model that inherits from it. Suppose we want to create a Student model with additional fields, such as enrollment_date and major. We can achieve this by extending the User model as follows:

python
from datetime import date
from typing import Optional

class Student(User):
    enrollment_date: date
    major: Optional[str] = None

Adding Validators to the Inherited Model

Validators are functions that validate and preprocess data for Pydantic models. They can be added to inherited models to enforce custom rules or modify data before it's stored in the model. To add a validator to our Student model, we use the @validator decorator:

python
from pydantic import validator

class Student(User):
    enrollment_date: date
    major: Optional[str] = None

    @validator("enrollment_date")
    def validate_enrollment_date(cls, enrollment_date):
        if enrollment_date > date.today():
            raise ValueError("Enrollment date must be in the past")
        return enrollment_date

Overriding Fields and Methods

In some cases, you might want to override a field or method in the inherited model to change its behavior. To do this, simply redefine the field or method in the derived class:

python
class Staff(User):
    role: str
    email: str  # Overriding the EmailStr type in the User model

    def get_role(self):
        return f"Staff role: {self.role}"

In this example, we overrode the email field to accept any string instead of validating it as an email address. Additionally, we added a new method get_role to the Staff class.

Practical Examples of Pydantic Inheritance

In this chapter, I will delve into practical examples of Pydantic inheritance that demonstrate the power and flexibility of this feature in real-world applications.

User Authentication

Consider a web application that has multiple user types, such as Admin, Customer, and ContentCreator. Each user type may have its own unique set of attributes and functionality. By leveraging Pydantic inheritance, we can create a base User model and then extend it for each user type.

python
# Base User model
class User(BaseModel):
    id: int
    username: str
    password: str
    email: EmailStr

# Admin model
class Admin(User):
    access_level: int

    def grant_permission(self, target_user: User):
        # Implementation to grant permission to target_user

# Customer model
class Customer(User):
    shipping_address: str
    billing_address: str

    def place_order(self, order: Order):
        # Implementation to place an order

# ContentCreator model
class ContentCreator(User):
    bio: Optional[str] = None

    def create_content(self, content: Content):
        # Implementation to create content

Product Catalog

In an e-commerce application, you might have different types of products, such as Electronics, Clothing, and Furniture. Each product type could have unique attributes. Here's an example of how to use Pydantic inheritance to model these product types:

python
# Base Product model
class Product(BaseModel):
    id: int
    name: str
    price: float
    description: str

# Electronics model
class Electronics(Product):
    brand: str
    warranty_period: int

# Clothing model
class Clothing(Product):
    size: str
    material: str
    gender: str

# Furniture model
class Furniture(Product):
    dimensions: Tuple[float, float, float]
    weight: float
    material: str

Blog Post Models

In a blogging platform, you might have various types of content, such as Article, Video, and ImageGallery. Each content type could have unique attributes and functionality. You can use Pydantic inheritance to create models for these content types:

python
# Base Content model
class Content(BaseModel):
    id: int
    title: str
    author: User
    created_at: datetime

# Article model
class Article(Content):
    body: str
    tags: List[str]

# Video model
class Video(Content):
    video_url: HttpUrl
    duration: int

# ImageGallery model
class ImageGallery(Content):
    images: List[HttpUrl]
    thumbnail: HttpUrl

References

https://docs.pydantic.dev/usage/models/

Ryusei Kakujo

researchgatelinkedingithub

Focusing on data science for mobility

Bench Press 100kg!