wrappers.py 13 KB

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