Coverage for extras/models/dashboard.py: 45%
31 statements
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-10 18:35 +0000
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-10 18:35 +0000
1from django.db import models
2from django.utils.translation import gettext_lazy as _
4from extras.dashboard.utils import get_widget_class
6__all__ = (
7 'Dashboard',
8)
11class Dashboard(models.Model):
12 user = models.OneToOneField(
13 to='users.User',
14 on_delete=models.CASCADE,
15 related_name='dashboard'
16 )
17 layout = models.JSONField(
18 verbose_name=_('layout'),
19 default=list
20 )
21 config = models.JSONField(
22 verbose_name=_('config'),
23 default=dict
24 )
26 class Meta:
27 verbose_name = _('dashboard')
28 verbose_name_plural = _('dashboards')
30 def get_widget(self, id):
31 """
32 Instantiate and return a widget by its ID
33 """
34 id = str(id)
35 config = dict(self.config[id]) # Copy to avoid mutating instance data
36 widget_class = get_widget_class(config.pop('class'))
37 return widget_class(id=id, **config)
39 def get_layout(self):
40 """
41 Return the dashboard's configured layout, suitable for rendering with gridstack.js.
42 """
43 widgets = []
44 for grid_item in self.layout:
45 widget = self.get_widget(grid_item['id'])
46 widget.set_layout(grid_item)
47 widgets.append(widget)
48 return widgets
50 def add_widget(self, widget, x=None, y=None):
51 """
52 Add a widget to the dashboard, optionally specifying its X & Y coordinates.
53 """
54 id = str(widget.id)
55 self.config[id] = {
56 'class': widget.name,
57 'title': widget.title,
58 'color': widget.color,
59 'config': widget.config,
60 }
61 self.layout.append({
62 'id': id,
63 'h': widget.height,
64 'w': widget.width,
65 'x': x,
66 'y': y,
67 })
69 def delete_widget(self, id):
70 """
71 Delete a widget from the dashboard.
72 """
73 id = str(id)
74 del self.config[id]
75 self.layout = [
76 item for item in self.layout if item['id'] != id
77 ]