Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do add an assembled field to a Pydantic model

Say I have model

class UserDB(BaseModel):
    first_name: Optional[str] = None
    last_name: Optional[str] = None

How do I make another model that is constructed from this one and has a field that changes based on the fields in this model?

For instance, something like this

class User(BaseModel):
    full_name: str = first_name + ' ' + last_name

Constructed like this maybe

User.parse_obj(UserDB)

Thanks!

like image 421
Florian van Kampen-Wright Avatar asked Aug 19 '20 17:08

Florian van Kampen-Wright


People also ask

What is pydantic field?

Pydantic is a useful library for data parsing and validation. It coerces input types to the declared type (using type hints), accumulates all the errors using ValidationError & it's also well documented making it easily discoverable.

What is Orm_mode in pydantic?

ORM Mode (aka Arbitrary Class Instances) Pydantic models can be created from arbitrary class instances to support models that map to ORM objects. To do this: The Config property orm_mode must be set to True . The special constructor from_orm must be used to create the model instance.

What is pydantic Constr?

constr is a specific type that give validation rules regarding this specific type. You have equivalent for all classic python types.

What is pydantic BaseModel in Python?

pydantic allows custom data types to be defined or you can extend validation with methods on a model decorated with the validator decorator. dataclasses integration. As well as BaseModel , pydantic provides a dataclass decorator which creates (almost) vanilla Python dataclasses with input data parsing and validation.


1 Answers

If you do not want to keep first_name and last_name in User then you can

  • customize __init__.
  • use validator for setting full_name.

Both methods do what you want:

from typing import Optional
from pydantic import BaseModel, validator


class UserDB(BaseModel):
    first_name: Optional[str] = None
    last_name: Optional[str] = None


class User_1(BaseModel):
    location: str  # for a change
    full_name: Optional[str] = None

    def __init__(self, user_db: UserDB, **data):
        super().__init__(full_name=f"{user_db.first_name} {user_db.last_name}", **data)


user_db = UserDB(first_name="John", last_name="Stark")
user = User_1(user_db, location="Mars")
print(user)


class User_2(BaseModel):
    first_name: Optional[str] = None
    last_name: Optional[str] = None
    full_name: Optional[str] = None

    @validator('full_name', always=True)
    def ab(cls, v, values) -> str:
        return f"{values['first_name']} {values['last_name']}"


user = User_2(**user_db.dict())
print(user)

output

location='Mars' full_name='John Stark'
first_name='John' last_name='Stark' full_name='John Stark'

UPDATE: For working with response_model you can customize __init__ in such way:

class User_1(BaseModel):
    location: str  # for a change
    full_name: Optional[str] = None

    # def __init__(self, user_db: UserDB, **data):
    def __init__(self, first_name, last_name, **data):
        super().__init__(full_name=f"{first_name} {last_name}", **data)


user_db = UserDB(first_name="John", last_name="Stark")
user = User_1(**user_db.dict(), location="Mars")
print(user)
like image 133
alex_noname Avatar answered Sep 21 '22 12:09

alex_noname