from sqlalchemy.orm.exc import NoResultFound from wtforms import ValidationError try: from wtforms.validators import InputRequired except ImportError: from wtforms.validators import Required as InputRequired from flask_admin._compat import filter_list class Unique(object): """Checks field value unicity against specified table field. :param get_session: A function that return a SQAlchemy Session. :param model: The model to check unicity against. :param column: The unique column. :param message: The error message. """ field_flags = ('unique', ) def __init__(self, db_session, model, column, message=None): self.db_session = db_session self.model = model self.column = column self.message = message def __call__(self, form, field): # databases allow multiple NULL values for unique columns if field.data is None: return try: obj = (self.db_session.query(self.model) .filter(self.column == field.data) .one()) if not hasattr(form, '_obj') or not form._obj == obj: if self.message is None: self.message = field.gettext(u'Already exists.') raise ValidationError(self.message) except NoResultFound: pass class ItemsRequired(InputRequired): """ A version of the ``InputRequired`` validator that works with relations, to require a minimum number of related items. """ def __init__(self, min=1, message=None): super(ItemsRequired, self).__init__(message=message) self.min = min def __call__(self, form, field): items = filter_list(lambda e: not field.should_delete(e), field.entries) if len(items) < self.min: if self.message is None: message = field.ngettext( u"At least %(num)d item is required", u"At least %(num)d items are required", self.min ) else: message = self.message raise ValidationError(message) def valid_currency(form, field): from sqlalchemy_utils import Currency try: Currency(field.data) except (TypeError, ValueError): raise ValidationError(field.gettext(u'Not a valid ISO currency code (e.g. USD, EUR, CNY).')) def valid_color(form, field): from colour import Color try: Color(field.data) except (ValueError): raise ValidationError(field.gettext(u'Not a valid color (e.g. "red", "#f00", "#ff0000").')) class TimeZoneValidator(object): """ Tries to coerce a TimZone object from input data """ def __init__(self, coerce_function): self.coerce_function = coerce_function def __call__(self, form, field): try: self.coerce_function(str(field.data)) except Exception: msg = u'Not a valid timezone (e.g. "America/New_York", "Africa/Johannesburg", "Asia/Singapore").' raise ValidationError(field.gettext(msg))