Commit 358ab3a5 authored by PJ Janse van Rensburg's avatar PJ Janse van Rensburg

Add support for more sqla utils fields.

parent 6f78ec70
......@@ -384,7 +384,7 @@ class ChoiceTypeNotEqualFilter(FilterNotEqual):
break
if choice_type:
# != can exclude NULL values, so "or_ == None" needed to be added
return query.filter(or_(column != choice_type, column == None))
return query.filter(or_(column != choice_type, column == None)) # noqa: E711
else:
return query
......@@ -431,7 +431,7 @@ class ChoiceTypeNotLikeFilter(FilterNotLike):
choice_types.append(type)
if choice_types:
# != can exclude NULL values, so "or_ == None" needed to be added
return query.filter(or_(column.notin_(choice_types), column == None))
return query.filter(or_(column.notin_(choice_types), column == None)) # noqa: E711
else:
return query
......
......@@ -14,7 +14,7 @@ from flask_admin.model.helpers import prettify_name
from flask_admin._backwards import get_property
from flask_admin._compat import iteritems, text_type
from .validators import Unique
from .validators import Unique, valid_currency, valid_color, TimeZoneValidator
from .fields import (QuerySelectField, QuerySelectMultipleField,
InlineModelFormList, InlineHstoreList, HstoreForm)
from flask_admin.model.fields import InlineFormField
......@@ -341,11 +341,41 @@ class AdminModelConverter(ModelConverterBase):
def convert_time(self, field_args, **extra):
return form.TimeField(**field_args)
@converts('EmailType')
@converts('sqlalchemy_utils.types.arrow.ArrowType')
def convert_arrow_time(self, field_args, **extra):
return form.DateTimeField(**field_args)
@converts('sqlalchemy_utils.types.email.EmailType')
def convert_email(self, field_args, **extra):
field_args['validators'].append(validators.Email())
return fields.StringField(**field_args)
@converts('sqlalchemy_utils.types.url.URLType')
def convert_url(self, field_args, **extra):
field_args['validators'].append(validators.URL())
return fields.StringField(**field_args)
@converts('sqlalchemy_utils.types.ip_address.IPAddressType')
def convert_ip_address(self, field_args, **extra):
field_args['validators'].append(validators.IPAddress())
return fields.StringField(**field_args)
@converts('sqlalchemy_utils.types.color.ColorType')
def convert_color(self, field_args, **extra):
field_args['validators'].append(valid_color)
return fields.StringField(**field_args)
@converts('sqlalchemy_utils.types.currency.CurrencyType')
def convert_currency(self, field_args, **extra):
field_args['validators'].append(valid_currency)
return fields.StringField(**field_args)
@converts('sqlalchemy_utils.types.timezone.TimezoneType')
def convert_timezone(self, column, field_args, **extra):
field_args['validators'].append(TimeZoneValidator(coerce_function=column.type._coerce))
return fields.StringField(**field_args)
@converts('Integer') # includes BigInteger and SmallInteger
def handle_integer_types(self, column, field_args, **extra):
unsigned = getattr(column.type, 'unsigned', False)
......@@ -371,7 +401,8 @@ class AdminModelConverter(ModelConverterBase):
field_args['validators'].append(validators.MacAddress())
return fields.StringField(**field_args)
@converts('sqlalchemy.dialects.postgresql.base.UUID')
@converts('sqlalchemy.dialects.postgresql.base.UUID',
'sqlalchemy_utils.types.uuid.UUIDType')
def conv_PGUuid(self, field_args, **extra):
field_args.setdefault('label', u'UUID')
field_args['validators'].append(validators.UUID())
......
......@@ -3,12 +3,14 @@ from sqlalchemy.ext.associationproxy import _AssociationList
from flask_admin.model.typefmt import BASE_FORMATTERS, EXPORT_FORMATTERS, \
DETAIL_FORMATTERS, list_formatter
from sqlalchemy.orm.collections import InstrumentedList
from sqlalchemy_utils.types import Choice
from sqlalchemy_utils import Choice
from arrow import Arrow
def choice_formatter(view, choice):
"""
Return label of selected choice
see https://sqlalchemy-utils.readthedocs.io/
:param choice:
sqlalchemy_utils Choice, which has a `code` and a `value`
......@@ -16,6 +18,28 @@ def choice_formatter(view, choice):
return choice.value
def arrow_formatter(view, arrow_time):
"""
Return human-friendly string of the time relative to now.
see https://arrow.readthedocs.io/
:param arrow_time:
Arrow object for handling datetimes
"""
return arrow_time.humanize()
def arrow_export_formatter(view, arrow_time):
"""
Return string representation of Arrow object
see https://arrow.readthedocs.io/
:param arrow_time:
Arrow object for handling datetimes
"""
return arrow_time.format()
DEFAULT_FORMATTERS = BASE_FORMATTERS.copy()
EXPORT_FORMATTERS = EXPORT_FORMATTERS.copy()
DETAIL_FORMATTERS = DETAIL_FORMATTERS.copy()
......@@ -24,12 +48,9 @@ DEFAULT_FORMATTERS.update({
InstrumentedList: list_formatter,
_AssociationList: list_formatter,
Choice: choice_formatter,
Arrow: arrow_formatter,
})
EXPORT_FORMATTERS.update({
Choice: choice_formatter,
})
DETAIL_FORMATTERS.update({
Choice: choice_formatter,
Arrow: arrow_export_formatter,
})
from sqlalchemy.orm.exc import NoResultFound
from sqlalchemy_utils import Currency
from colour import Color
from wtforms import ValidationError
try:
......@@ -66,3 +68,32 @@ class ItemsRequired(InputRequired):
message = self.message
raise ValidationError(message)
def valid_currency(form, field):
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):
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))
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment