diff --git a/ormar/models/helpers/validation.py b/ormar/models/helpers/validation.py index b3e8e15..fb66b71 100644 --- a/ormar/models/helpers/validation.py +++ b/ormar/models/helpers/validation.py @@ -303,11 +303,10 @@ def populate_choices_validators(model: Type["Model"]) -> None: # noqa CCR001 """ fields_with_choices = [] if not meta_field_not_set(model=model, field_name="model_fields"): - if hasattr(model, "_choices_fields"): - return - model._choices_fields = set() + if not hasattr(model, "_choices_fields"): + model._choices_fields = set() for name, field in model.Meta.model_fields.items(): - if check_if_field_has_choices(field): + if check_if_field_has_choices(field) and name not in model._choices_fields: fields_with_choices.append(name) validator = make_generic_validator(generate_validator(field)) model.__fields__[name].validators.append(validator) diff --git a/tests/test_inheritance_and_pydantic_generation/test_validators_are_inherited.py b/tests/test_inheritance_and_pydantic_generation/test_validators_are_inherited.py new file mode 100644 index 0000000..eafce40 --- /dev/null +++ b/tests/test_inheritance_and_pydantic_generation/test_validators_are_inherited.py @@ -0,0 +1,70 @@ +import enum + +import databases +import pydantic +import pytest +import sqlalchemy +from pydantic import ValidationError + +import ormar +from tests.settings import DATABASE_URL + +metadata = sqlalchemy.MetaData() +database = databases.Database(DATABASE_URL) + + +class BaseMeta(ormar.ModelMeta): + database = database + metadata = metadata + + +class BaseModel(ormar.Model): + class Meta: + abstract = True + + id: int = ormar.Integer(primary_key=True) + + +class EnumExample(str, enum.Enum): + A = "A" + B = "B" + C = "C" + + +class ModelExample(BaseModel): + class Meta(BaseMeta): + tablename = "examples" + + str_field: str = ormar.String(min_length=5, max_length=10, nullable=False) + enum_field: str = ormar.String( + max_length=1, nullable=False, choices=list(EnumExample) + ) + + @pydantic.validator("str_field") + def validate_str_field(cls, v): + if " " not in v: + raise ValueError("must contain a space") + return v + + +ModelExampleCreate = ModelExample.get_pydantic(exclude={"id"}) + + +def test_ormar_validator(): + ModelExample(str_field="a aaaaaa", enum_field="A") + with pytest.raises(ValidationError) as e: + ModelExample(str_field="aaaaaaa", enum_field="A") + assert "must contain a space" in str(e) + with pytest.raises(ValidationError) as e: + ModelExample(str_field="a aaaaaaa", enum_field="Z") + assert "not in allowed choices" in str(e) + + +def test_pydantic_validator(): + ModelExampleCreate(str_field="a aaaaaa", enum_field="A") + with pytest.raises(ValidationError) as e: + ModelExampleCreate(str_field="aaaaaaa", enum_field="A") + assert "must contain a space" in str(e) + with pytest.raises(ValidationError) as e: + ModelExampleCreate(str_field="a aaaaaaa", enum_field="Z") + assert "not in allowed choices" in str(e)