wrappers.py 12 KB

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