How to validate input to get the following Dict
passed!
d = dict()
d['en'] = 'English content'
d['it'] = 'Italian content'
d['es'] = 'Spanish content'
print(d)
# {'en': 'English content', 'it': 'Italian content', 'es': 'Spanish content'}
In this example, keys are ISO 639-1 codes
using pycountry
python package.
code = 'en'
pycountry.languages.get(alpha_2=code.upper()).alpha_2 # = 'en'
The point is how to validate keys using pydantic reusable validator or any other methods?
And validate values either to be str
or int
?
Pydantic model schema
should be similar to this sample :
# products/model.py
from sqlalchemy import Column, String, Integer
from sqlalchemy.ext.declarative import declarative_base
from custom_field import Translatable
Base = declarative_base()
class Model(Base):
__tablename__ = "products"
id = Column(Integer, unique=True, index=True)
name = Column(Translatable())
price = Column(Integer)
# products/pydantic.py
from pydantic import BaseModel
import custom_pydantic_field
class BaseSchema(BaseModel):
id: int
class CreateSchema(BaseSchema):
name: custom_pydantic_field.translatable
price: int
Keep in mind reusability in other models/schemas.
CodePudding user response:
Create pydantic custom class
# validators/translated_field.py
from typing import Dict
from pydantic import ValidationError
from pydantic.error_wrappers import ErrorWrapper
import pycountry
class Translatable(Dict):
"""
Validate Translation Dict Field (Json) where Language is Key and Translation as Value
Languages : ISO 639-1 code
Translation : Int, str, None
ref:
- https://pydantic-docs.helpmanual.io/usage/types/#classes-with-__get_validators__
By: Khalid Murad
"""
@property
def __translation_interface__(self):
return self.dict()
@classmethod
def __get_validators__(cls):
yield cls.validate
@classmethod
def validate(cls, base_dictionary):
result = dict()
dictionary = dict()
errors = []
dictionary = base_dictionary
for key in dictionary:
try:
parsed_language = pycountry.languages.get(alpha_2=key.upper())
except ValueError as exc:
errors.append(ErrorWrapper(Exception(f"Invalid language: {key}."), loc="language"))
if not parsed_language:
errors.append(ErrorWrapper(Exception(f"Invalid language: {key}."), loc="language"))
if isinstance(dictionary[key], int | str | None):
result[key] = dictionary[key]
else:
errors.append(ErrorWrapper(Exception(f"Invalid content for language: {key}."), loc=("language","content")))
if errors:
raise ValidationError(
errors,
cls,
)
return cls(result)
Then use it in you schema/pydantic model like:
# products/pydantic.py
from pydantic import BaseModel
from validators.translated_field import Translatable
class BaseSchema(BaseModel):
id: int
class CreateSchema(BaseSchema):
name: Translatable
...your code
And use normal JSON
field in SQLALchemy model!
# products/model.py
...
from sqlalchemy import Column, JSON
...
class Model(Base):
name = Column(JSON, nullable=True)
...