'SQLAlchemy implicit type conversion and Date validation

Let's assume this model class:

class Person(db.Model):
    __tablename__ = "person"

    date_of_birth = db.Column(db.Date)

With person being an instance of Person, I can do the following in my unit test:

person.date_of_birth = "05/05/2000"

So far, so good, and this code has been in production for some time. Now someone reports a bug that there are persons with dates of birth in the future. Dates of birth in the future are invalid in my context and I want to prevent them from entering the data store, so I add a validator to the model class:

@validates("date_of_birth")
def validate_date_of_birth(self, key, date_of_birth):
    if date_of_birth and date_of_birth > datetime.now().date():
        raise BirthDayException("A date of birth must not be in the future.")
    return date_of_birth

This will, somewhat understandably, break my unit test and throw an exception when I do the assignment from above:

>       if date_of_birth and date_of_birth > datetime.datetime.now().date():
E       TypeError: '>' not supported between instances of 'str' and 'datetime.date'

I don't quite understand where I should address it, though.

  • Should I change my unit test and not assign a string value to a date property? But there could be other places in the code where this is happening, leaving me exposed to regression.
  • Or should I check for the correct data type in the validator and convert it if necessary?
  • Or can I somehow tell SqlAlchemy to do the auto-conversion that it normally does BEFORE the validator is invoked? That would be the nicest solution.

Thanks for your input.



Solution 1:[1]

Fwiw, I ended up doing the unthinkable - check for the type and convert to date if it is a string:

if type(date_of_birth) is str:
    date_of_birth = datetime.datetime.strptime(date_of_birth, "%m/%d/%Y").date()

    if date_of_birth and date_of_birth > datetime.datetime.now().date():
        raise BirthDayException("A date of birth must not be in the future.")

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 cdonner