wrappers.py 12 KB

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