Search code examples
pythondesign-patternstypesfastapipydantic

Define common Pydantic fields, use subsets of them in models


Setup

I have a long list of variables to be used in email templates.

Example
cust_name: str  
bill_address: str  
ship_address: str  
ref_num: int
# ...list continues

Overlapping combinations of these appear in the templates, which I've modeled using Pydantic.

Example
class TemplateA(BaseModel):
    cust_name: str
    bill_address: str

class TemplateB(BaseModel):
    cust_name: str
    ref_num: int

class TemplateC(BaseModel):
    bill_address: str 
    ship_address: str

# ...and so on

Question

I'd like to know if there's a recommended way to centrally define my variable: type combos so I'm not repeating myself, and if I change a variable name or a type, those changes are reflected everywhere.

Pydantic model inheritance isn't working for me because so many combinations of fields are mixed and matched across template models. I'm open to the idea of changing my approach entirely if there's a better way. Thanks!


Solution

  • My Answer

    You can use pydantic.create_model.

    My Example

    from pydantic import Field, create_model
    
    # [field definitions]
    
    cust_name = str, Field(default='ccc')
    bill_address = str, Field(default='bbb')
    ship_address = str, Field()
    ref_num = int, Field()
    
    
    # [models]
    
    TemplateA = create_model(
        'TemplateA',
        cust_name=cust_name,
        bill_address=bill_address,
    )
    TemplateB = create_model(
        'TemplateB',
        cust_name=cust_name,
        ref_num=ref_num,
    )
    TemplateC = create_model(
        'TemplateC',
        bill_address=bill_address,
        ship_address=ship_address,
    )
    
    
    # [constructions]
    
    print(TemplateA().model_dump())
    # > {'cust_name': 'ccc', 'bill_address': 'bbb'}
    
    print(TemplateB(ref_num=1).model_dump())
    # > {'cust_name': 'ccc', 'ref_num': 1}
    
    print(TemplateC(ship_address='ship_address').model_dump())
    # > {'bill_address': 'bbb', 'ship_address': 'ship_address'}