dashboard.py 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. from importlib import import_module
  2. from django.core.urlresolvers import reverse
  3. from django.template.loader import render_to_string
  4. from jet.dashboard import modules
  5. from jet.dashboard.models import UserDashboardModule
  6. from django.core.context_processors import csrf
  7. from django.utils.translation import ugettext_lazy as _
  8. from jet.ordered_set import OrderedSet
  9. from jet.utils import get_admin_site_name
  10. class Dashboard(object):
  11. """
  12. Base dashboard class. All custom dashboards should inherit it.
  13. """
  14. #: Number of columns in which widgets can be placed
  15. columns = 2
  16. #: Dashboard Modules (widgets) that dashboard is filled with, when the user open it for the first time
  17. #:
  18. #: List of dashboard module **instances**
  19. children = None
  20. #: Dashboard Modules (widgets) that user can add to dashboard at any time
  21. # (not created when the user open dashboard for the first time)
  22. #:
  23. #: List of dashboard module **classes**
  24. available_children = None
  25. app_label = None
  26. context = None
  27. modules = None
  28. class Media:
  29. css = ()
  30. js = ()
  31. def __init__(self, context, **kwargs):
  32. for key in kwargs:
  33. if hasattr(self.__class__, key):
  34. setattr(self, key, kwargs[key])
  35. self.children = self.children or []
  36. self.available_children = self.available_children or []
  37. self.set_context(context)
  38. def set_context(self, context):
  39. self.context = context
  40. self.init_with_context(context)
  41. self.load_modules()
  42. def init_with_context(self, context):
  43. """
  44. Override this method to fill your custom **Dashboard** class with widgets.
  45. You should add your widgets to ``children`` and ``available_children`` attributes.
  46. Usage example:
  47. .. code-block:: python
  48. from django.utils.translation import ugettext_lazy as _
  49. from jet.dashboard import modules
  50. from jet.dashboard.dashboard import Dashboard, AppIndexDashboard
  51. class CustomIndexDashboard(Dashboard):
  52. columns = 3
  53. def init_with_context(self, context):
  54. self.available_children.append(modules.LinkList)
  55. self.children.append(modules.LinkList(
  56. _('Support'),
  57. children=[
  58. {
  59. 'title': _('Django documentation'),
  60. 'url': 'http://docs.djangoproject.com/',
  61. 'external': True,
  62. },
  63. {
  64. 'title': _('Django "django-users" mailing list'),
  65. 'url': 'http://groups.google.com/group/django-users',
  66. 'external': True,
  67. },
  68. {
  69. 'title': _('Django irc channel'),
  70. 'url': 'irc://irc.freenode.net/django',
  71. 'external': True,
  72. },
  73. ],
  74. column=0,
  75. order=0
  76. ))
  77. """
  78. pass
  79. def load_module(self, module_fullname):
  80. package, module_name = module_fullname.rsplit('.', 1)
  81. package = import_module(package)
  82. module = getattr(package, module_name)
  83. return module
  84. def create_initial_module_models(self, user):
  85. module_models = []
  86. i = 0
  87. for module in self.children:
  88. column = module.column if module.column is not None else i % self.columns
  89. order = module.order if module.order is not None else int(i / self.columns)
  90. module_models.append(UserDashboardModule.objects.create(
  91. title=module.title,
  92. app_label=self.app_label,
  93. user=user.pk,
  94. module=module.fullname(),
  95. column=column,
  96. order=order,
  97. settings=module.dump_settings(),
  98. children=module.dump_children()
  99. ))
  100. i += 1
  101. return module_models
  102. def load_modules(self):
  103. module_models = UserDashboardModule.objects.filter(
  104. app_label=self.app_label,
  105. user=self.context['request'].user.pk
  106. ).all()
  107. if len(module_models) == 0:
  108. module_models = self.create_initial_module_models(self.context['request'].user)
  109. loaded_modules = []
  110. for module_model in module_models:
  111. module_cls = module_model.load_module()
  112. if module_cls is not None:
  113. module = module_cls(model=module_model, context=self.context)
  114. loaded_modules.append(module)
  115. self.modules = loaded_modules
  116. def render(self):
  117. context = self.context
  118. context.update({
  119. 'columns': range(self.columns),
  120. 'modules': self.modules,
  121. 'app_label': self.app_label,
  122. })
  123. context.update(csrf(context['request']))
  124. return render_to_string('jet.dashboard/dashboard.html', context)
  125. def render_tools(self):
  126. context = self.context
  127. context.update({
  128. 'children': self.children,
  129. 'app_label': self.app_label,
  130. 'available_children': self.available_children
  131. })
  132. context.update(csrf(context['request']))
  133. return render_to_string('jet.dashboard/dashboard_tools.html', context)
  134. def media(self):
  135. unique_css = OrderedSet()
  136. unique_js = OrderedSet()
  137. for js in getattr(self.Media, 'js', ()):
  138. unique_js.add(js)
  139. for css in getattr(self.Media, 'css', ()):
  140. unique_css.add(css)
  141. for module in self.modules:
  142. for js in getattr(module.Media, 'js', ()):
  143. unique_js.add(js)
  144. for css in getattr(module.Media, 'css', ()):
  145. unique_css.add(css)
  146. class Media:
  147. css = list(unique_css)
  148. js = list(unique_js)
  149. return Media
  150. class AppIndexDashboard(Dashboard):
  151. def get_app_content_types(self):
  152. return self.app_label + '.*',
  153. def models(self):
  154. return self.app_label + '.*',
  155. class DefaultIndexDashboard(Dashboard):
  156. columns = 3
  157. def init_with_context(self, context):
  158. self.available_children.append(modules.LinkList)
  159. self.available_children.append(modules.Feed)
  160. site_name = get_admin_site_name(context)
  161. # append a link list module for "quick links"
  162. self.children.append(modules.LinkList(
  163. _('Quick links'),
  164. layout='inline',
  165. draggable=False,
  166. deletable=False,
  167. collapsible=False,
  168. children=[
  169. [_('Return to site'), '/'],
  170. [_('Change password'),
  171. reverse('%s:password_change' % site_name)],
  172. [_('Log out'), reverse('%s:logout' % site_name)],
  173. ],
  174. column=0,
  175. order=0
  176. ))
  177. # append an app list module for "Applications"
  178. self.children.append(modules.AppList(
  179. _('Applications'),
  180. exclude=('auth.*',),
  181. column=1,
  182. order=0
  183. ))
  184. # append an app list module for "Administration"
  185. self.children.append(modules.AppList(
  186. _('Administration'),
  187. models=('auth.*',),
  188. column=2,
  189. order=0
  190. ))
  191. # append a recent actions module
  192. self.children.append(modules.RecentActions(
  193. _('Recent Actions'),
  194. 10,
  195. column=0,
  196. order=1
  197. ))
  198. # append a feed module
  199. self.children.append(modules.Feed(
  200. _('Latest Django News'),
  201. feed_url='http://www.djangoproject.com/rss/weblog/',
  202. limit=5,
  203. column=1,
  204. order=1
  205. ))
  206. # append another link list module for "support".
  207. self.children.append(modules.LinkList(
  208. _('Support'),
  209. children=[
  210. {
  211. 'title': _('Django documentation'),
  212. 'url': 'http://docs.djangoproject.com/',
  213. 'external': True,
  214. },
  215. {
  216. 'title': _('Django "django-users" mailing list'),
  217. 'url': 'http://groups.google.com/group/django-users',
  218. 'external': True,
  219. },
  220. {
  221. 'title': _('Django irc channel'),
  222. 'url': 'irc://irc.freenode.net/django',
  223. 'external': True,
  224. },
  225. ],
  226. column=2,
  227. order=1
  228. ))
  229. class DefaultAppIndexDashboard(AppIndexDashboard):
  230. def init_with_context(self, context):
  231. self.available_children.append(modules.LinkList)
  232. self.children.append(modules.ModelList(
  233. title=_('Application models'),
  234. models=self.models(),
  235. column=0,
  236. order=0
  237. ))
  238. self.children.append(modules.RecentActions(
  239. include_list=self.get_app_content_types(),
  240. column=1,
  241. order=0
  242. ))
  243. class DashboardUrls(object):
  244. _urls = []
  245. def get_urls(self):
  246. return self._urls
  247. def register_url(self, url):
  248. self._urls.append(url)
  249. def register_urls(self, urls):
  250. self._urls.extend(urls)
  251. urls = DashboardUrls()