123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196 |
- #!/usr/bin/env python
- # -*- coding: utf-8 -*-
- # **************************************************************************
- # Copyright © 2016 jianglin
- # File Name: serializer.py
- # Author: jianglin
- # Email: xiyang0807@gmail.com
- # Created: 2016-12-13 22:08:23 (CST)
- # Last Update:星期一 2017-3-13 13:28:30 (CST)
- # By:
- # Description:
- # **************************************************************************
- from sqlalchemy import inspect
- from sqlalchemy.orm.interfaces import (ONETOMANY, MANYTOMANY)
- class PageInfo(object):
- def __init__(self, paginate):
- self.paginate = paginate
- def as_dict(self):
- pageinfo = {
- 'items': True,
- 'pages': self.paginate.pages,
- 'has_prev': self.paginate.has_prev,
- 'page': self.paginate.page,
- 'has_next': self.paginate.has_next,
- 'iter_pages': list(
- self.paginate.iter_pages(
- left_edge=1, left_current=2, right_current=3,
- right_edge=1))
- }
- return pageinfo
- class Field(object):
- def __init__(self, source, args={}, default=None):
- self.source = source
- self.args = args
- self.default = default
- def data(self, instance):
- if hasattr(instance, self.source):
- source = getattr(instance, self.source)
- if not callable(source):
- return source
- return source(**self.args)
- return self.default
- class Serializer(object):
- def __init__(self,
- instance,
- many=False,
- include=[],
- exclude=[],
- extra=[],
- depth=2):
- self.instance = instance
- self.many = many
- self.depth = depth
- self.include = include
- self.exclude = exclude
- self.extra = extra
- @property
- def data(self):
- meta = self.Meta
- if not self.include and hasattr(meta, 'include'):
- self.include = meta.include
- if not self.exclude and hasattr(meta, 'exclude'):
- self.exclude = meta.exclude
- if not self.extra and hasattr(meta, 'extra'):
- self.extra = meta.extra
- # if not self.depth:
- # self.depth = meta.depth if hasattr(meta, 'depth') else 2
- # if self.include and self.exclude:
- # raise ValueError('include and exclude can\'t work together')
- if self.many:
- return self._serializerlist(self.instance, self.depth)
- return self._serializer(self.instance, self.depth)
- def _serializerlist(self, instances, depth):
- results = []
- for instance in instances:
- result = self._serializer(instance, depth)
- if result:
- results.append(result)
- return results
- def _serializer(self, instance, depth):
- result = {}
- if depth == 0:
- return result
- depth -= 1
- model_class = self.get_model_class(instance)
- inp = self.get_inspect(model_class)
- model_data = self._serializer_model(inp, instance, depth)
- relation_data = self._serializer_relation(inp, instance, depth)
- extra_data = self._serializer_extra(instance)
- result.update(model_data)
- result.update(relation_data)
- result.update(extra_data)
- return result
- def _serializer_extra(self, instance):
- extra = self.extra
- result = {}
- for e in extra:
- # extra_column = getattr(self, e)
- # if isinstance(extra_column, Field):
- # result[e] = extra_column.data(instance)
- # else:
- extra_column = getattr(instance, e)
- result[e] = extra_column if not callable(
- extra_column) else extra_column()
- return result
- def _serializer_model(self, inp, instance, depth):
- result = {}
- model_columns = self.get_model_columns(inp)
- for column in model_columns:
- result[column] = getattr(instance, column)
- return result
- def _serializer_relation(self, inp, instance, depth):
- result = {}
- relation_columns = self.get_relation_columns(inp)
- for relation in relation_columns:
- column = relation.key
- serializer = Serializer
- if hasattr(self, column):
- serializer = getattr(self, column)
- if relation.direction in [ONETOMANY, MANYTOMANY
- ] and relation.uselist:
- children = getattr(instance, column)
- if relation.lazy == 'dynamic':
- children = children.all()
- result[column] = serializer(
- children,
- many=True,
- exclude=[relation.back_populates],
- depth=depth).data if children else []
- else:
- child = getattr(instance, column)
- if relation.lazy == 'dynamic':
- child = child.first()
- result[column] = serializer(
- child,
- many=False,
- exclude=[relation.back_populates],
- depth=depth).data if child else {}
- return result
- def get_model_class(self, instance):
- return getattr(instance, '__class__')
- def get_inspect(self, model_class):
- return inspect(model_class)
- def get_model_columns(self, inp):
- if self.include:
- model_columns = [
- column.name for column in inp.columns
- if column.name in self.include
- ]
- elif self.exclude:
- model_columns = [
- column.name for column in inp.columns
- if column.name not in self.exclude
- ]
- else:
- model_columns = [column.name for column in inp.columns]
- return model_columns
- def get_relation_columns(self, inp):
- if self.include:
- relation_columns = [
- relation for relation in inp.relationships
- if relation.key in self.include
- ]
- elif self.exclude:
- relation_columns = [
- relation for relation in inp.relationships
- if relation.key not in self.exclude
- ]
- else:
- relation_columns = [relation for relation in inp.relationships]
- return relation_columns
- class Meta:
- depth = 2
- include = []
- exclude = []
- extra = []
|