Home > other >  pydantic basemodel "field" for validation purposes only
pydantic basemodel "field" for validation purposes only

Time:06-03

Consider the follwoing code illustrating use of the pydantic BaseModel with validation:

from pydantic import BaseModel, validator

class User(BaseModel, frozen=True):
    id_key: int
    user_id: int

    @validator('user_id')
    def id_check(cls, v, values):
        if v > 2 * values['id_key']   1:
            raise ValueError('id check failed.')
        return v

user_dict = {'user_id': 10, 'id_key': 60}
u = User(**user_dict)

Now, in my application, I don't really want id_key to be a regular, accessible field in model instances like u--its sole purpose is for validating user_id. For my example, is there a way to have access to id_key for validation purposes but not have it be a standard field?

CodePudding user response:

The values argument you have in your id_check function being the internal dict of attributes already validated for your instance, if you need to have id_key only at instantiation time for checking and not after that, you could simply remove it from values.

from pydantic import BaseModel, validator

class User(BaseModel, frozen=True):
    id_key: int
    user_id: int

    @validator('user_id')
    def id_check(cls, v, values):
        if v > 2 * values['id_key']   1:
            raise ValueError('id check failed.')
        values.pop('id_key')
        return v
user_dict = {'user_id': 10, 'id_key': 60}
u = User(**user_dict)
print(u)
# output:
# user_id=10

There is one additional improvement I'd like to suggest for your code: in its present state, as pydantic runs the validations of all the fields before returning the validation errors, if you pass something completely invalid for id_key like "abc" for example, or omit it, it won't be added to values, and the validation of user_id will crash with KeyError: 'id_key', swallowing all the rest of the validation process and returning no sensible message.

user_dict = {'user_id': 10, 'id_key': 'abc'}
u = User(**user_dict)
# output:
# KeyError: 'id_key'

This is not very explicit, and might cause issues with your application if you expect a pydantic ValidationError. You might want to check that id_key is indeed present in values and raise the error cleanly if not.

from pydantic import BaseModel, validator

class User(BaseModel, frozen=True):
    id_key: int
    user_id: int

    @validator('user_id')
    def id_check(cls, v, values):
        if 'id_key' not in values or v > 2 * values['id_key']   1:
            raise ValueError('id check failed.')
        values.pop('id_key')
        return v
user_dict = {'user_id': 10, 'id_key': 'abc'}
u = User(**user_dict)
# output:
# pydantic.error_wrappers.ValidationError: 2 validation errors for User
# id_key
#   value is not a valid integer (type=type_error.integer)
# user_id
#   id check failed.(type=value_error)
  • Related