Pydantic: Change default value of inherited attribute using Field

Created on 4 Jan 2020  路  1Comment  路  Source: samuelcolvin/pydantic

Question

Output of python -c "import pydantic.utils; print(pydantic.utils.version_info())":

             pydantic version: 1.3
            pydantic compiled: False
                 install path: /Users/michaeloliver/git/PennySaveAPI/venv/lib/python3.7/site-packages/pydantic
               python version: 3.7.1 (v3.7.1:260ec2c36a, Oct 20 2018, 03:13:28)  [Clang 6.0 (clang-600.0.57)]
                     platform: Darwin-19.0.0-x86_64-i386-64bit
     optional deps. installed: ['email-validator']

Take this example:

from typing import Optional

from pydantic import BaseModel, Field, EmailStr


# Shared properties
class UserBase(BaseModel):
    email: EmailStr = Field(..., description="Valid email address.")
    first_name: str = Field(..., description="Users first name.")
    last_name: str = Field(..., description="Users last name.")


# Properties to receive via API on creation
class UserCreate(UserBase):
    password: str = Field(
        ...,
        regex=r"^(?=(.*[a-zA-Z].*){2,})(?=.*\d.*)(?=.*\W.*)[a-zA-Z0-9\S]{8,32}$",
        description="Password requirements. Min 8 - Max 32 character length.\n"
                    "At least two letters (not case sensitive), one number and one special character.\n"
                    "No spaces are allowed.",
        min_length=8,
        max_length=32
    )


# Properties to receive via API on update
class UserUpdate(UserBase):
    email: Optional[EmailStr] = Field(None, description="Valid email address.")
    first_name: Optional[str] = Field(None, description="Users first name.")
    last_name: Optional[str] = Field(None, description="Users last name.")
    password: Optional[str] = Field(
        None,
        regex=r"^(?=(.*[a-zA-Z].*){2,})(?=.*\d.*)(?=.*\W.*)[a-zA-Z0-9\S]{8,32}$",
        description="Password requirements. Min 8 - Max 32 character length.\n"
                    "At least two letters (not case sensitive), one number and one special character.\n"
                    "No spaces are allowed.",
        min_length=8,
        max_length=32
    )
...

I was using inheritance to try and reduce the code and simplify some of my models. I am using the Field function to specify extra validation information. In UserCreate the password is required but within the UserUpdate model it is optional. Is there a way for to inherit class attributes with their validation information but change their default values?

I am still new to Pydantic :)

question

Most helpful comment

Found the solution! Fields can have validation information added through the Config class. Field isn't needed then in any subclasses. Required/optional fields can then be set with standard Python type hints. Subclasses can override the Optional status of fields by just re declaring them.

See below:

from typing import Optional
from datetime import datetime

from pydantic import BaseModel, Field, EmailStr


# Shared properties
class UserBase(BaseModel):
    email: Optional[EmailStr] = None
    first_name: Optional[str] = None
    last_name: Optional[str] = None

    class Config:
        orm_mode = True
        fields = {
            "email": {"description": "Valid email address."},
            "first_name": {"description": "Users first name."},
            "last_name": {"description": "Users last name."},
            "password": {
                "regex": r"^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$%^&*-]).{8,32}$",
                "description": "Password requirements.\n"
                "Min 8 - Max 32 character length.\n"
                "At least one upper case letter.\n"
                "At least one lower case letter.\n"
                "At least one digit.\n"
                "At least one special character.\n",
            },
        }


# Properties to receive via API on creation
class UserCreate(UserBase):
    email: EmailStr
    password: str


# Properties to receive via API on update
class UserUpdate(UserBase):
    password: Optional[str] = None

Docs

>All comments

Found the solution! Fields can have validation information added through the Config class. Field isn't needed then in any subclasses. Required/optional fields can then be set with standard Python type hints. Subclasses can override the Optional status of fields by just re declaring them.

See below:

from typing import Optional
from datetime import datetime

from pydantic import BaseModel, Field, EmailStr


# Shared properties
class UserBase(BaseModel):
    email: Optional[EmailStr] = None
    first_name: Optional[str] = None
    last_name: Optional[str] = None

    class Config:
        orm_mode = True
        fields = {
            "email": {"description": "Valid email address."},
            "first_name": {"description": "Users first name."},
            "last_name": {"description": "Users last name."},
            "password": {
                "regex": r"^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$%^&*-]).{8,32}$",
                "description": "Password requirements.\n"
                "Min 8 - Max 32 character length.\n"
                "At least one upper case letter.\n"
                "At least one lower case letter.\n"
                "At least one digit.\n"
                "At least one special character.\n",
            },
        }


# Properties to receive via API on creation
class UserCreate(UserBase):
    email: EmailStr
    password: str


# Properties to receive via API on update
class UserUpdate(UserBase):
    password: Optional[str] = None

Docs

Was this page helpful?
0 / 5 - 0 ratings

Related issues

bradodarb picture bradodarb  路  22Comments

sm-Fifteen picture sm-Fifteen  路  45Comments

DrPyser picture DrPyser  路  19Comments

chopraaa picture chopraaa  路  18Comments

jaheba picture jaheba  路  25Comments