Commits

Maciej Wiatrzyk committed 5b93a4f

ext.sqlalchemy: add support for SQLAlchemy < 0.7 and some tests

  • Participants
  • Parent commits 19585f3

Comments (0)

Files changed (2)

File tests/ext_sqlalchemy.py

 #!/usr/bin/env python
 
+import re
+
+from datetime import datetime, timedelta
+
 from sqlalchemy import create_engine, ForeignKey
 from sqlalchemy.schema import MetaData, Table, Column
 from sqlalchemy.types import String, Integer, Date
-from sqlalchemy.orm import sessionmaker, relationship, backref
+from sqlalchemy.orm import sessionmaker, relationship, backref, validates
 from sqlalchemy.ext.declarative import declarative_base
 
 from unittest import TestCase
         class Student(Model):
             __tablename__ = "student"
             id = Column(Integer, primary_key=True)
+            gender = Column(String(1), nullable=False)
             full_name = Column(String(255), nullable=False, unique=True)
             dob = Column(Date(), nullable=True)
             current_school_id = Column(Integer, ForeignKey(School.id),
             courses = relationship("Course", secondary=student_course,
                 backref=backref("students", lazy='dynamic'))
 
+            @validates('full_name')
+            def validate_fullname(self, key, value, form=None, field=None):
+                if re.match('[0-9]+', value):
+                    raise ValueError('digits are not allowed')
+                return value
+
+            @validates('gender')
+            def validate_gender(self, key, value, form=None, field=None):
+                if value not in ('M', 'F'):
+                    raise ValueError('invalid gender')
+                return value
+
         self.School = School
         self.Student = Student
 
         self.metadata.create_all(bind=engine)
         self.sess = Session()
 
+        self.sa_wrong = DummyPostData(
+            full_name=u'J0hn D03',  # see: validate_fullname
+            gender=u'male',  # see: validate_gender
+            dob=[u'1980-01-01'])
+
+        self.sa_correct = DummyPostData(
+            full_name=u'John Doe',
+            gender=u'M',
+            dob=[u'1980-01-01'])
+
+        self.sa_only = ['full_name', 'gender', 'dob']
+
     def test_nullable_field(self):
         student_form = model_form(self.Student, self.sess)()
         self.assertTrue(issubclass(Optional,
         self.assertTrue(issubclass(QuerySelectMultipleField,
             student_form._fields['courses'].__class__))
 
+    def test_sa_validators_disabled_wrong(self):
+        form = model_form(self.Student, only=self.sa_only)(self.sa_wrong)
+        self.assertTrue(form.validate())
+
+    def test_sa_validators_disabled_correct(self):
+        form = model_form(self.Student, only=self.sa_only)(self.sa_correct)
+        self.assertTrue(form.validate())
+
+    def test_sa_validators_enabled_wrong(self):
+        obj = self.Student()
+        form = model_form(self.Student, only=self.sa_only, use_sa_validators=True)(self.sa_wrong, obj=obj)
+        self.assertFalse(form.validate())
+
+    def test_sa_validators_enabled_correct(self):
+        obj = self.Student()
+        form = model_form(self.Student, only=self.sa_only, use_sa_validators=True)(self.sa_correct, obj=obj)
+        self.assertTrue(form.validate())
+
 
 class UniqueValidatorTest(TestCase):
     def setUp(self):

File wtforms/ext/sqlalchemy/orm.py

         # validators will require additional 'form' and 'field' keyword
         # arguments once called by WTForms
         if self.use_sa_validators:
-            validator = mapper.validators.get(prop.key)
+            validator = _sa_validator(model, mapper, prop)
             if validator is not None:
-                kwargs['validators'].append(_sa_validator(model, prop.key, validator))
+                kwargs['validators'].append(validator)
 
         return converter(model=model, mapper=mapper, prop=prop, column=column,
             field_args=kwargs)
 
 ### HELPERS
 
-def _sa_validator(model, key, validator):
+def _sa_validator(model, mapper, prop):
+    validators = getattr(mapper, 'validators', None)
+    if validators is None:  # Fallback for SQLAlchemy < 0.7
+        validators = {}
+        for name in dir(model):
+            if name.startswith('_'):
+                continue
+            value = getattr(model, name)
+            if hasattr(value, '__sa_validators__'):
+                for key in value.__sa_validators__:
+                    validators[key] = value
+    validator = validators.get(prop.key)
+    if validator is None:
+        return
+
     def __sa_validator(form, field):
         if not isinstance(form.obj, model):
             raise TypeError(
                 (model, type(form.obj)))
         validator(form.obj, field.name, field.data,
             form=form, field=field)
+
     __sa_validator.func_name = validator.func_name
     return __sa_validator