Suppose I have a SQLAlchemy 2.0 model representing cars. It incorporates a simple validation routine (Reference) for the string attributes:
from sqlalchemy.orm import Mapped from sqlalchemy.orm import mapped_column from sqlalchemy.orm import validates class Base(DeclarativeBase): pass class Car(Base): __tablename__ = 'car' id: Mapped[int] = mapped_column(primary_key=True) make: Mapped[str] = mapped_column() # Tesla model: Mapped[str] = mapped_column() # S color: Mapped[str] = mapped_column() # Black # Ensure that the input data is not null @validates('make', 'model', 'color') # <============ def validate_string(self, key, value): if not value: raise ValueError(f'The {key} must be entered') return value Now, let's consider that I need to add 30 additional string attributes to the model and validate them. Given the current validation routine setup, I'll have to add 30 additional attribute names in the validates decorator:
@validates('make', 'model', 'color', 'str_attr_4', 'str_attr_5', 'str_attr_6', ..., 'str_attr_33') I find it very tedious and I'm sure there's a smarter way to proceed.
I have a solution in mind, but I'm struggling to implement it: since we already know the type of each attribute thanks to the typing hints provided in Mapped, it would be great if something like the following were possible:
class Car(Base): __tablename__ = 'car' id: Mapped[int] = mapped_column(primary_key=True) make: Mapped[str] = mapped_column() # Tesla model: Mapped[str] = mapped_column() # S color: Mapped[str] = mapped_column() # Black str_attr_4: Mapped[str] = mapped_column() str_attr_5: Mapped[str] = mapped_column() str_attr_6: Mapped[str] = mapped_column() ... str_attr_33: Mapped[str] = mapped_column() # Ensure that the input data is not null @validates(*[attr_name for attr_name in dir(self) if attr_name is mapped to str]) # <============ def validate_string(self, key, value): if not value: raise ValueError(f'The {key} must be entered') return value I made several attempts and a lot of research to construct the *[attr_name for attr_name in dir(self) if attr_name is mapped to str] expression, but I couldn't get it to work.
Do you have any suggestions on how to achieve this, or perhaps other ideas to simplify the validation routine?
Caritself soselfis not available. That is just a fact from Python. I think you would need a metaclass to do something like this. If you combinemapped_columnanddataclassess ( to define a well defined and typed constructor) I think you can accomplish something like this.