jazzband / jsonmodels

jsonmodels is library to make it easier for you to deal with structures that are converted to, or read from JSON.
http://jsonmodels.readthedocs.org/en/latest/
BSD 3-Clause "New" or "Revised" License
334 stars 51 forks source link

ListField: Add validation support for the elements values in the list #110

Open avrahamshukron opened 6 years ago

avrahamshukron commented 6 years ago

Right now the ListField class supports type validation on its elements, and validation agains the list itself (length etc.) But there is no easy way to specify validators that should be applied to every item in the list.

For example, I might want a ListField of ints, where all the items must be in the range [0, 10].

One might create the following validator:

class ElementsValidator(object):
    def __init__(self, *item_validators):
        self.item_validators = item_validators

    def validate(self, value):
        for item in value:
            for v in self.item_validators:
                v.validate(item)

class Foo(models.Base):
     my_list = fields.ListField(int, validators=(
             ElementsValidator(validators.Min(0), validators.Max(10))
         ))

While this example will work, It has some problems:

  1. It will be very hard to modify the schema from this validator, as it needs to touch some schema elements created by the ListField itself, which might cause conflicts.
  2. It will be very hard to support different validation for each supported type in the list.

Since the type of each element of the list, and its validators actually creates one schema, I think that this feature should be implemented by the library itself, and not by custom validator.

I have no idea how to implement this cleanly without breaking the current API of ListField though...

DanielSchiavini commented 6 years ago

This is included in our fork: https://github.com/beregond/jsonmodels/pull/120

I don't see the problem with your 1st point, since the schema is applied to field_schema["items"].

The 2nd point is not a responsibility of the list, if you are using sub-models each model can implement their own validation. Native types (str, int, etc) will probably not be able to be validated by the same validator. In this case you'd need to create a custom validator.