dashboard.py 9.6 KB

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