Validating a field multiple times with different @validates decorators is causing them to be skipped

Issue #3776 resolved
Steven Leggett created an issue

If a field has multiple @validates decorators it will not consistently validate each of them properly and cause subsequent @validates to be skipped.

Example: the second validator, validate_field_positive_number, will not get run.

    @validates('email')
    def validate_test_123(self, key, field):
        return field

    @validates('email')
    def validate_field_positive_number(self, key, field):
        if True:
            raise ValidationError('failed multiple validation')
        return field

If you run it the first time. Validation will pass. If you remove/delete the validate_test_123 decorator and validation, the second one will always work.

The problem with this is that with a larger data model it's very clean to create generic @validates decorators for things like missing required fields, data types, etc. So having multiple @validates for the same fields is needed.

Thanks, Steve

Comments (8)

  1. Steven Leggett reporter

    SQLAlchemy==1.0.12 Also using Flask and Flask-SQLAlchemy==2.1 but having a feeling this is a core issue.

  2. Mike Bayer repo owner

    hello -

    This is not a documented behavior so I think this would be an enhancement. However, I don't see how it can work. One @validates is likely to be dependent on the other, because if validator A changes the value in some way, validator B will often be dependent on that change having taken place or not. It follows then that the validators would need to be called in a specific order. However, how would this order be determined? We would only have access here to perhaps the order in which @validates() was called. But if you arranged your classes differently or even the order of imports changed, this would break. This seems quite brittle. So I'm not sure if this feature is feasible.

  3. Steven Leggett reporter

    Hi Michael,

    Thanks for the quick response. The validators I've been using are not changing data, but instead just ensuring the value/structures are in the format I'd require. I see your point if the validators are changing the data that could then become an issue.

    Just thinking that there could be two different types of validators. One for immutable and one for mutable. Multiple validators for immutable: @validates_chain Single validator for mutable. @validates

    I guess I find it kind of messy having to repeat the same validation code in multiple @validates for various fields but if this is by design, then I'm happy to go with it. I'm really loving SQLalchemy.

    I might create a PR to update the docs (http://docs.sqlalchemy.org/en/latest/orm/mapped_attributes.html#simple-validators) so this becomes more visible, so others don't try to also use multiple @validates for a single field.

  4. Mike Bayer repo owner

    we can make it raise for conflicting @validators. that might be more self-documenting.

  5. Mike Bayer repo owner

    Raise when two validators conflict

    Two @validates decorators that make use of the same name is not supported. Raise an exception.

    Change-Id: Ia3e89ffdc9ef345a0de258e2ac0ac5e0bd421c61 Fixes: #3776

    → <<cset 117997cd5b84>>

  6. Log in to comment