serializer.py 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. # **************************************************************************
  4. # Copyright © 2016 jianglin
  5. # File Name: serializer.py
  6. # Author: jianglin
  7. # Email: xiyang0807@gmail.com
  8. # Created: 2016-12-13 22:08:23 (CST)
  9. # Last Update:星期一 2017-3-13 13:28:30 (CST)
  10. # By:
  11. # Description:
  12. # **************************************************************************
  13. from sqlalchemy import inspect
  14. from sqlalchemy.orm.interfaces import (ONETOMANY, MANYTOMANY)
  15. class PageInfo(object):
  16. def __init__(self, paginate):
  17. self.paginate = paginate
  18. def as_dict(self):
  19. pageinfo = {
  20. 'items': True,
  21. 'pages': self.paginate.pages,
  22. 'has_prev': self.paginate.has_prev,
  23. 'page': self.paginate.page,
  24. 'has_next': self.paginate.has_next,
  25. 'iter_pages': list(
  26. self.paginate.iter_pages(
  27. left_edge=1, left_current=2, right_current=3,
  28. right_edge=1))
  29. }
  30. return pageinfo
  31. class Field(object):
  32. def __init__(self, source, args={}, default=None):
  33. self.source = source
  34. self.args = args
  35. self.default = default
  36. def data(self, instance):
  37. if hasattr(instance, self.source):
  38. source = getattr(instance, self.source)
  39. if not callable(source):
  40. return source
  41. return source(**self.args)
  42. return self.default
  43. class Serializer(object):
  44. def __init__(self,
  45. instance,
  46. many=False,
  47. include=[],
  48. exclude=[],
  49. extra=[],
  50. depth=2):
  51. self.instance = instance
  52. self.many = many
  53. self.depth = depth
  54. self.include = include
  55. self.exclude = exclude
  56. self.extra = extra
  57. @property
  58. def data(self):
  59. meta = self.Meta
  60. if not self.include and hasattr(meta, 'include'):
  61. self.include = meta.include
  62. if not self.exclude and hasattr(meta, 'exclude'):
  63. self.exclude = meta.exclude
  64. if not self.extra and hasattr(meta, 'extra'):
  65. self.extra = meta.extra
  66. # if not self.depth:
  67. # self.depth = meta.depth if hasattr(meta, 'depth') else 2
  68. # if self.include and self.exclude:
  69. # raise ValueError('include and exclude can\'t work together')
  70. if self.many:
  71. return self._serializerlist(self.instance, self.depth)
  72. return self._serializer(self.instance, self.depth)
  73. def _serializerlist(self, instances, depth):
  74. results = []
  75. for instance in instances:
  76. result = self._serializer(instance, depth)
  77. if result:
  78. results.append(result)
  79. return results
  80. def _serializer(self, instance, depth):
  81. result = {}
  82. if depth == 0:
  83. return result
  84. depth -= 1
  85. model_class = self.get_model_class(instance)
  86. inp = self.get_inspect(model_class)
  87. model_data = self._serializer_model(inp, instance, depth)
  88. relation_data = self._serializer_relation(inp, instance, depth)
  89. extra_data = self._serializer_extra(instance)
  90. result.update(model_data)
  91. result.update(relation_data)
  92. result.update(extra_data)
  93. return result
  94. def _serializer_extra(self, instance):
  95. extra = self.extra
  96. result = {}
  97. for e in extra:
  98. # extra_column = getattr(self, e)
  99. # if isinstance(extra_column, Field):
  100. # result[e] = extra_column.data(instance)
  101. # else:
  102. extra_column = getattr(instance, e)
  103. result[e] = extra_column if not callable(
  104. extra_column) else extra_column()
  105. return result
  106. def _serializer_model(self, inp, instance, depth):
  107. result = {}
  108. model_columns = self.get_model_columns(inp)
  109. for column in model_columns:
  110. result[column] = getattr(instance, column)
  111. return result
  112. def _serializer_relation(self, inp, instance, depth):
  113. result = {}
  114. relation_columns = self.get_relation_columns(inp)
  115. for relation in relation_columns:
  116. column = relation.key
  117. serializer = Serializer
  118. if hasattr(self, column):
  119. serializer = getattr(self, column)
  120. if relation.direction in [ONETOMANY, MANYTOMANY
  121. ] and relation.uselist:
  122. children = getattr(instance, column)
  123. if relation.lazy == 'dynamic':
  124. children = children.all()
  125. result[column] = serializer(
  126. children,
  127. many=True,
  128. exclude=[relation.back_populates],
  129. depth=depth).data if children else []
  130. else:
  131. child = getattr(instance, column)
  132. if relation.lazy == 'dynamic':
  133. child = child.first()
  134. result[column] = serializer(
  135. child,
  136. many=False,
  137. exclude=[relation.back_populates],
  138. depth=depth).data if child else {}
  139. return result
  140. def get_model_class(self, instance):
  141. return getattr(instance, '__class__')
  142. def get_inspect(self, model_class):
  143. return inspect(model_class)
  144. def get_model_columns(self, inp):
  145. if self.include:
  146. model_columns = [
  147. column.name for column in inp.columns
  148. if column.name in self.include
  149. ]
  150. elif self.exclude:
  151. model_columns = [
  152. column.name for column in inp.columns
  153. if column.name not in self.exclude
  154. ]
  155. else:
  156. model_columns = [column.name for column in inp.columns]
  157. return model_columns
  158. def get_relation_columns(self, inp):
  159. if self.include:
  160. relation_columns = [
  161. relation for relation in inp.relationships
  162. if relation.key in self.include
  163. ]
  164. elif self.exclude:
  165. relation_columns = [
  166. relation for relation in inp.relationships
  167. if relation.key not in self.exclude
  168. ]
  169. else:
  170. relation_columns = [relation for relation in inp.relationships]
  171. return relation_columns
  172. class Meta:
  173. depth = 2
  174. include = []
  175. exclude = []
  176. extra = []