Luiscri
Luiscri

Reputation: 1037

Replace field value if validation fails

I have defined the following model:

from datetime import datetime
from typing import Optional

from pydantic import BaseModel, Field

class InvalidTransaction(BaseModel):
    error_ts: datetime = Field(default_factory=datetime.utcnow)
    transaction_ts: Optional[datetime] = None
    filename: str
    index: int
    id: Optional[int] = None
    message: str

There are two fields transaction_ts and id which are retrieved from a file, and for this reason, I can't assure that they will be provided in the right format. However, those are not critical fields for my model and I need to create an object even if those two fields do not pass the validation.

How can I set those two fields to None if they are not provided in the correct format?

Example:

print(InvalidTransaction(**{
    'transaction_ts': '2022-03 12:30:21', # invalid datetime
    'filename': 'myfile.csv',
    'index': 3,
    'id': 4,
    'message': 'Invalid transaction found'
}).json())

''' Returns:
pydantic.error_wrappers.ValidationError: 1 validation error for InvalidTransaction
transaction_ts
  invalid datetime format (type=value_error.datetime)
'''

And I need the following output:

{"error_ts": "2022-08-11T17:34:36.837724", "transaction_ts": null, "filename": "myfile.csv", "index": 3, "id": 4, "message": "Invalid transaction found"}

Upvotes: 1

Views: 641

Answers (1)

Yaakov Bressler
Yaakov Bressler

Reputation: 12008

You can use validators to accomplish this:

from datetime import datetime
from typing import Optional

from pydantic import BaseModel, Field, validator

class InvalidTransaction(BaseModel):
    error_ts: datetime = Field(default_factory=datetime.utcnow)
    transaction_ts: Optional[datetime] = None
    filename: str
    index: int
    id: Optional[int] = None
    message: str


    # Custom validator here
    @validator('id', pre=True)
    def int_or_none(cls, v):
        try:
            return int(v)
        except ValueError:
            return None

    @validator('transaction_ts', pre=True)
    def timestamp_or_none(cls, v):
        try:
            # You might need to modify this logic
            return datetime.fromisoformat(v)
        except ValueError:
            # You could return current timestamp here if you'd like
            return None

Upvotes: 1

Related Questions