wrappers.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  1. # -*- coding: utf-8 -*-
  2. __author__ = 'marcos.medeiros'
  3. from rapid.registry import registry, Action
  4. from rapid import filters
  5. import itertools
  6. from django.db import models
  7. from rapid import permissions
  8. class InstanceData:
  9. def __init__(self, instance, request=None, excludes=None, creator=None, fields=None):
  10. excludes = [] if excludes is None else excludes
  11. self.model = ModelData(type(instance), request, excludes, creator, fields)
  12. self.instance = instance
  13. self.request = request
  14. self.excludes = excludes if excludes else []
  15. self.creator = creator
  16. self._fields = fields if fields else self.model.fields()
  17. def values(self):
  18. r = []
  19. o = self.instance
  20. for f in self.model.fields():
  21. if f.is_relation:
  22. r.append(self._value_of_field(o, f))
  23. else:
  24. r.append(self._value_of_field(o, f))
  25. return r
  26. def _value_of_field(self, instance, field):
  27. """
  28. Returns the value of the given field.
  29. ::return A tuple, with the actual value of the field, a boolean that is true iff
  30. the value is iterable, and a sequence of URLs for the viewers of the instances
  31. of the first element, or False if there are no viewers.
  32. """
  33. if hasattr(instance, field.accessor_name()):
  34. v = getattr(instance, field.accessor_name())
  35. else: # Many to many relations without value may disappear
  36. return [], True
  37. if hasattr(v, '__iter__'):
  38. return (v, ()), True
  39. if hasattr(v, 'all'):
  40. return [(x, InstanceData(x, self.request, creator=(self, field))) for x in v.all()], True
  41. if isinstance(v, models.Model):
  42. return (v, InstanceData(v, self.request, creator=(self, field))), False
  43. return (v, ()), False
  44. def fields_and_values(self):
  45. r = []
  46. for field in self.model.fields():
  47. value, is_multiple = self._value_of_field(self.instance, field)
  48. r.append((field, value, is_multiple))
  49. return r
  50. def is_controlled(self):
  51. return self.model.is_controlled()
  52. def can_read(self):
  53. return self.has_permission(self.request, 'view')
  54. def can_write(self):
  55. return self.has_permission(self.request, 'edit')
  56. def view_url(self):
  57. return registry.get_url_of_action(self.model.model, "view", pk=self.instance.pk)
  58. def edit_url(self):
  59. url = registry.get_url_of_action(self.model.model, "edit", pk=self.instance.pk)
  60. by = self.creator
  61. if by:
  62. dt, fd = by
  63. if fd.one_to_one or fd.one_to_many:
  64. # Do not change the parent of the viewer.
  65. return url + "?default=" + fd.field.name + ":" + str(dt.object.pk)
  66. if fd.many_to_one or fd.many_to_many:
  67. return url
  68. return url
  69. def remove_url(self):
  70. return registry.get_url_of_action(self.model.model, "delete", pk=self.instance.pk)
  71. def create_url(self):
  72. return registry.get_url_of_action(self.model.model, "add")
  73. def list_url(self):
  74. return registry.get_url_of_action(self.model.model, "list")
  75. def select_url(self):
  76. return registry.get_url_of_action(self.model.model, "select")
  77. def actions(self):
  78. r = []
  79. acts = registry.model_entry(self.model.model)
  80. if self.request and acts:
  81. for a in acts.values():
  82. if self.has_permission(self.request, a.action.name) and\
  83. a.action.visibility > Action.Visibility.hidden:
  84. r.append((a, a.get_url(self.instance)))
  85. return r
  86. def model_actions(self):
  87. r = []
  88. for (a, u) in self.actions():
  89. if not a.action.query_parameters:
  90. r.append((a, u))
  91. return r
  92. def instance_actions(self):
  93. r = []
  94. for (a, u) in self.actions():
  95. if a.action.query_parameters:
  96. r.append((a, u))
  97. return r
  98. def list_actions(self):
  99. r = []
  100. for (a, u) in self.instance_actions():
  101. if a.action.visibility == Action.Visibility.list:
  102. r.append((a, u))
  103. return r
  104. def has_permission(self, request, action_name):
  105. m = registry.model_entry(self.model.model).get(action_name)
  106. if m:
  107. perm = m.permission.instances
  108. return permissions.has_instance(self.model, perm(request), self.instance)
  109. return False
  110. def __unicode__(self):
  111. return unicode(self.instance)
  112. def __str__(self):
  113. return str(self.model) + ': ' + str(self.instance.pk)
  114. class ModelData:
  115. def __init__(self, model, request=None, excludes=None, creator=None, fields=None):
  116. excludes = [] if excludes is None else excludes
  117. self.model = model
  118. self.request = request
  119. self.excludes = excludes if excludes else []
  120. self.creator = creator
  121. self._fields = [self.field_by_name(f) for f in fields] if fields else self.all_fields()
  122. def model_name(self):
  123. # noinspection PyProtectedMember
  124. return unicode(self.model._meta.verbose_name)
  125. def model_name_plural(self):
  126. # noinspection PyProtectedMember
  127. return unicode(self.model._meta.verbose_name_plural)
  128. def default_manager(self):
  129. # noinspection PyProtectedMember
  130. return self.model._default_manager
  131. def all_fields(self):
  132. r = []
  133. relations = []
  134. for f in itertools.chain(self.local_fields(), self.related_fields()):
  135. if f.is_relation():
  136. relations.append(f)
  137. else:
  138. if f.name not in self.excludes:
  139. r.append(f)
  140. for f in relations:
  141. if f.name not in self.excludes:
  142. r.append(f)
  143. return r
  144. def fields(self):
  145. return self._fields
  146. def local_fields(self):
  147. r = []
  148. # noinspection PyProtectedMember
  149. for f in self.model._meta.local_fields:
  150. if f.name not in self.excludes:
  151. r.append(FieldData(f, self.request))
  152. # noinspection PyProtectedMember
  153. for f in self.model._meta.local_many_to_many:
  154. if f.name not in self.excludes:
  155. r.append(FieldData(f, self.request))
  156. return r
  157. def related_fields(self):
  158. # noinspection PyProtectedMember
  159. return [FieldData(f, self.request) for f in self.model._meta.get_all_related_objects()]
  160. def is_controlled(self):
  161. return registry.is_controlled(self.model)
  162. def can_read(self):
  163. if self.can_write():
  164. return True
  165. vw = registry.model_entry(self.model)['view'].permission(self.request)
  166. if vw:
  167. return vw.exists()
  168. return False
  169. def can_write(self):
  170. ed = registry.model_entry(self.model)['edit'].permission(self.request)
  171. if ed:
  172. return ed.exists()
  173. return False
  174. def create_url(self):
  175. return registry.get_url_of_action(self.model, "add")
  176. def list_url(self):
  177. return registry.get_url_of_action(self.model, "list")
  178. def select_url(self):
  179. return registry.get_url_of_action(self.model, "select")
  180. def actions(self):
  181. r = []
  182. acts = registry.model_entry(self.model)
  183. if self.request and acts:
  184. for a in acts.values():
  185. if self.has_permission(self.request, a.action.name) and\
  186. not a.action.query_parameters and\
  187. a.action.visibility > Action.Visibility.hidden:
  188. r.append((a, a.get_url()))
  189. return r
  190. def has_permission(self, request, action_name):
  191. m = registry.model_entry(self.model).get(action_name)
  192. if m:
  193. return bool(m.permission.model(request))
  194. return False
  195. def field_by_name(self, field_name):
  196. # noinspection PyProtectedMember
  197. return FieldData(self.model._meta.get_field(field_name), self.request)
  198. def __unicode__(self):
  199. return unicode(self.model)
  200. def __str__(self):
  201. return 'Model: ' + str(self.model)
  202. class FieldData:
  203. def __init__(self, field, request=None):
  204. self.field = field
  205. self.request = request
  206. @classmethod
  207. def from_model(cls, model, field_name):
  208. ff = ModelData(model).fields()
  209. for f in ff:
  210. if f.bare_name() == unicode(field_name):
  211. return f
  212. return None
  213. def bare_name(self):
  214. return unicode(self.field.name)
  215. def accessor_name(self):
  216. if hasattr(self.field, 'get_accessor_name'):
  217. return unicode(self.field.get_accessor_name())
  218. return unicode(self.field.name)
  219. def name(self):
  220. if self.is_auto() and self.is_relation():
  221. return self.related_model().model_name_plural() + u' - ' + self.related_field().name()
  222. if hasattr(self.field, "verbose_name"):
  223. return unicode(self.field.verbose_name)
  224. return unicode(self.field.name)
  225. def name_plural(self):
  226. if self.is_auto() and self.is_relation():
  227. return self.related_model().model_name_plural() + u' - ' + self.related_field().name_plural()
  228. if hasattr(self.field, "verbose_name_plural"):
  229. return unicode(self.field.verbose_name_plural)
  230. return self.name() + "s"
  231. def is_relation(self):
  232. return self.field.is_relation
  233. def is_multiple(self):
  234. if not self.is_relation():
  235. return False
  236. if self.field.one_to_many:
  237. return True
  238. if self.field.many_to_many:
  239. return True
  240. return False
  241. def related_model(self):
  242. if hasattr(self.field, "related_model"):
  243. return ModelData(self.field.related_model)
  244. if hasattr(self.field, "to"):
  245. return ModelData(self.field.to)
  246. return None
  247. def related_field(self):
  248. if hasattr(self.field, "field"):
  249. return FieldData(self.field.field, self.request)
  250. return None
  251. def is_auto(self):
  252. return self.field.auto_created
  253. def is_weak(self):
  254. if not self.is_relation():
  255. return False
  256. f = self.field
  257. if hasattr(f, "many_to_many") and f.many_to_many:
  258. return False
  259. if hasattr(f, "many_to_one") and self.field.many_to_one:
  260. return False
  261. if hasattr(self.field, "get_related_field"):
  262. o = self.field.get_related_field
  263. if self.field.one_to_one or self.field.one_to_many:
  264. if hasattr(o, "required"):
  265. return o.required
  266. return True
  267. if isinstance(f, models.ForeignKey):
  268. # noinspection PyUnresolvedReferences,PyProtectedMember
  269. return self.related_model()._meta.pk.name
  270. return False
  271. def filter_html(self):
  272. return filters.Filter.selection_type_html(self, self.request)
  273. def __str__(self):
  274. return self.bare_name()
  275. class ValueData:
  276. def __init__(self, value, field):
  277. self.value = value
  278. self.field = field
  279. def can_view(self):
  280. if self.field.is_relation():
  281. o = self.field.related_model()
  282. return registry.is_controlled(o)
  283. return False
  284. def is_multiple(self):
  285. return self.field.is_multiple()
  286. def __str__(self):
  287. return str(self.field) + ': ' + str(self.value)