Home > Back-end >  Pydantic: how to parse non dict objects
Pydantic: how to parse non dict objects

Time:03-23

The following data is input

data = {
    'campaigns': [
        {
            'title': 'GBP',
            'geo_segment': 'WW',
            'ac_type': 'Value',
            'conversion': 'soft',
            'asset_type': 'ALL',
            'date': '22.04.21',
            'name': 'GBP_WW_1_core_22.04.21',
            'budget': '2000',
            'cpa': '1,00'
        }
    ],
    'stages': [
        'pre',
        'post'
    ],
    'language_mode': 'all_en'
}

To parse campaigns, I use the parse_obj() method

campaigns = parse_obj_as(List[CampaignData], data['campaigns'])

class CampaignData(BaseModel):
    title: NonEmptyString
    geo_segment: NonEmptyString
    ......

It works.

How to validate the rest of the data (stages: List, language_mode: str), which is not of type dict?

class GoogleCheckCampaignStages(BaseModel):
    stages: List[str]
        
    
class GoogleCheckLanguageMode(BaseModel):
    language_mode: str

If I run

stages = parse_obj_as(List[GoogleCheckCampaignStages], data['stages'])

returns

value is not a valid dict (type=type_error.dict)

Same result with data['language_mode'].

If I try with parse_raw_as() method

parse_raw_as(GoogleCheckLanguageMode, data['language_mode'])

returns

json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)

So how to parse str and list values?

CodePudding user response:

The error you are encountering is because you are passing in data["stages"] which is just a list/array. It has no key called stages and therefore Pydantic doesn't know how to assign it.

Assuming that NonEmptyString is defined as below, I would suggest creating one model that processes the whole data object, for example like this:

from pydantic import BaseModel, parse_obj_as, constr
from typing import List

NonEmptyString = constr(min_length=1)

class CampaignData(BaseModel):
    title: NonEmptyString
    geo_segment: NonEmptyString
    # and so on ...

class Data(BaseModel):
    campaigns: List[CampaignData]
    stages: List[str]
    language_mode: str

parsed_data = parse_obj_as(Data, data)
print(parsed_data)
# campaigns=[CampaignData(title='GBP', geo_segment='WW', ...)] stages=['pre', 'post'] language_mode='all_en'

If you'd like to access only specific elements, you can easily do it like this:

print(parsed_data.stages)
# ['pre', 'post']
  • Related