# -*- coding: utf-8 -*-
from flask.ext.restful import fields as _fields, marshal_with as _marshal_with
from functools import wraps


def _wrap_field(field):
    class WrappedField(field):
        def format(self, value):
            return None if value is None else super(WrappedField, self).format(value)
        
        def output(self, key, obj):
            value = _fields.get_value(key if self.attribute is None else self.attribute, obj)
            return None if value is None else self.format(value)
    return WrappedField

_type_map = {
    # python_type: flask-restful field
    'str': _wrap_field(_fields.String),
    'int': _wrap_field(_fields.Integer),
    'float': _wrap_field(_fields.Float),
    'bool': _wrap_field(_fields.Boolean),
    'datetime': _wrap_field(_fields.DateTime)
}


def marshal_with_model(model, excludes=[]):
    """
      todo: support KeyedTuple

      help view methods return orm model object more easily (only face to flask-sqlalchemy)
      1. transform columns in model to fields that flask-restful can understand.
         use the 'excludes' argument, you can specify columns shouldn't appear in return value
      2. when you return query object directly, auto transform it to list

      example：
      model：
      Student
        id int
        name string
        age int

      class SomeApi(Resource):
        @marshal_with_model(Student, excludes=['id'])
        def get(self):
          return Student.query

      return value to client：
      [{"name": "student_a", "age": "16"}, {"name": "student_b", "age": 18}]
    """
    field_definition = {}
    for col in model.__table__.columns:
        if col.name not in excludes:
            field_definition[col.name] = _type_map[col.type.python_type.__name__]

    def decorated(f):
        @wraps(f)
        @_marshal_with(field_definition)
        def wrapper(*args, **kwargs):
            result = f(*args, **kwargs)
            return result if not _fields.is_indexable_but_not_string(result) else [v for v in result]
        return wrapper
    return decorated
@@ -17,16 +17,50 @@
 f-8 -*-%0A
+__all__ = %5B'marshal_with_model'%5D%0A%0A
 from fla
@@ -158,16 +158,28 @@
 t wraps%0A
+import time%0A
 %0A%0Adef _w
@@ -575,16 +575,264 @@
 dField%0A%0A
+%0Aclass _DateTimeField(_fields.Raw):%0A    %22%22%22Return a timestamp%22%22%22%0A%0A    def format(self, value):%0A        try:%0A            return time.mktime(value.timetuple())%0A        except AttributeError as ae:%0A            raise _fields.MarshallingException(ae)%0A%0A%0A
 _type_ma
@@ -1073,23 +1073,16 @@
 ld(_
-fields.
 DateTime
 )%0A%7D%0A
@@ -1077,16 +1077,21 @@
 DateTime
+Field
 )%0A%7D%0A%0A%0Ade

修改 datetime 的格式化方式