Skip to content

Commit c000f86

Browse files
committed
- update tests
1 parent 179ee9c commit c000f86

File tree

14 files changed

+77
-105
lines changed

14 files changed

+77
-105
lines changed

dashboards/component/base.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ def get_value(
130130
value = self.defer(request=request, object=self.object, filters=filters)
131131
else:
132132
value = self.defer
133+
133134
else:
134135
serializable = getattr(self.value, "serialize", None)
135136
if serializable:
@@ -154,6 +155,8 @@ def _get_media_from_definition(self) -> Optional[asset_definitions.Media]:
154155
if definition:
155156
return asset_definitions.Media(media=definition)
156157

158+
return None
159+
157160
def get_media(self) -> asset_definitions.Media:
158161
# component level media
159162
media = self._get_media_from_definition() or asset_definitions.Media()
@@ -166,6 +169,10 @@ def get_media(self) -> asset_definitions.Media:
166169
return media
167170

168171
def render_value(self, context: Context, call_deferred: bool = False) -> str:
172+
# if value is deferred and we are not ready to call it, return loading template
173+
if self.is_deferred and not call_deferred:
174+
return render_to_string(self.defer_loading_template_name)
175+
169176
request = context.get("request")
170177
if request:
171178
filters = (

dashboards/component/chart/serializers.py

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import json
2-
from typing import Any, Dict, List, Optional
2+
from typing import Any, Dict, List, Optional, Type
33

44
from django.core.exceptions import ImproperlyConfigured
5+
from django.db.models import Model
56
from django.template.loader import render_to_string
67

78
import asset_definitions
@@ -18,7 +19,9 @@ class ModelDataMixin:
1819

1920
class Meta:
2021
fields: Optional[List[str]] = None
21-
model: Optional[str] = None
22+
model: Optional[Model] = None
23+
24+
_meta: Type["ModelDataMixin.Meta"]
2225

2326
def get_fields(self) -> Optional[List[str]]:
2427
# TODO: for some reason mypy complains about this one line
@@ -56,9 +59,13 @@ class PlotlyChartSerializerMixin:
5659
template_name: str = "dashboards/components/chart/plotly.html"
5760
meta_layout_attrs = ["title", "width", "height"]
5861
layout: Optional[Dict[str, Any]] = None
59-
displayModeBar: Optional[bool] = True
60-
staticPlot: Optional[bool] = False
61-
responsive: Optional[bool] = True
62+
63+
_meta: Type[Any]
64+
65+
class Meta:
66+
displayModeBar: Optional[bool] = True
67+
staticPlot: Optional[bool] = False
68+
responsive: Optional[bool] = True
6269

6370
def empty_chart(self) -> str:
6471
return json.dumps(
@@ -123,14 +130,16 @@ def render(cls, template_id, **kwargs) -> str:
123130
context = {
124131
"template_id": template_id,
125132
"value": value,
126-
"displayModeBar": self.displayModeBar,
127-
"staticPlot": self.staticPlot,
128-
"responsive": self.responsive,
133+
"displayModeBar": self._meta.displayModeBar,
134+
"staticPlot": self._meta.staticPlot,
135+
"responsive": self._meta.responsive,
129136
}
130137
return render_to_string(cls.template_name, context)
131138

132139

133140
class BaseChartSerializer(ClassWithMeta, asset_definitions.MediaDefiningClass):
141+
_meta: Type[Any]
142+
134143
class Meta:
135144
title: Optional[str] = None
136145
width: Optional[int] = None
@@ -165,6 +174,9 @@ class PlotlyChartSerializer(PlotlyChartSerializerMixin, BaseChartSerializer):
165174
Serializer to convert data into a plotly js format
166175
"""
167176

177+
class Meta(PlotlyChartSerializerMixin.Meta, BaseChartSerializer.Meta):
178+
pass
179+
168180
class Media:
169181
js = ("dashboards/vendor/js/plotly.min.js",)
170182

@@ -174,3 +186,8 @@ class ChartSerializer(ModelDataMixin, PlotlyChartSerializer):
174186
Default chart serializer to read data from a django model
175187
and serialize it to something plotly js can render
176188
"""
189+
190+
class Meta(ModelDataMixin.Meta, PlotlyChartSerializer.Meta):
191+
pass
192+
193+
_meta: Type["ChartSerializer.Meta"]

dashboards/component/table/mixins.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
from typing import Any, Dict, List, Tuple, Union
1+
from collections.abc import Iterable
2+
from typing import Any, Dict, List, Tuple, Type, Union
23

34
from django.core.exceptions import FieldDoesNotExist
45
from django.core.paginator import Page, Paginator
@@ -34,7 +35,7 @@ def filter(qs: QuerySet, fields: List[str], filters: Dict[str, Any]) -> QuerySet
3435

3536
@staticmethod
3637
def sort(
37-
qs: QuerySet, fields: List[str], filters: Dict[str, Any], force_lower: bool
38+
qs: QuerySet, fields: List[Any], filters: Dict[str, Any], force_lower: bool
3839
) -> QuerySet:
3940
"""
4041
Apply ordering to a queryset based on the order[{field}][column] column request params.
@@ -140,29 +141,32 @@ def count(data: List) -> int:
140141

141142

142143
class TableDataProcessorMixin:
144+
_meta: Type[Any]
145+
143146
@classmethod
144147
def get_data_processor(cls, data):
145148
if isinstance(data, QuerySet):
146149
return TableQuerysetProcessor
147-
elif isinstance(data, List):
150+
elif isinstance(data, Iterable):
148151
return TableListProcessor
149152

150153
raise Exception("data must be either a queryset or a list")
151154

152155
@classmethod
153156
def filter(
154-
cls, data: Union[QuerySet, List], fields: List[str], filters: Dict[str, Any]
157+
cls, data: Union[QuerySet, List], filters: Dict[str, Any]
155158
) -> Union[List, QuerySet]:
159+
fields = list(cls._meta.columns)
156160
return cls.get_data_processor(data).filter(data, fields, filters)
157161

158162
@classmethod
159163
def sort(
160164
cls,
161165
data: Union[QuerySet, List],
162-
fields: List[str],
163166
filters: Dict[str, Any],
164-
force_lower: bool,
165167
) -> Union[List, QuerySet]:
168+
force_lower = cls._meta.force_lower
169+
fields = list(cls._meta.columns)
166170
return cls.get_data_processor(data).sort(data, fields, filters, force_lower)
167171

168172
@classmethod

dashboards/component/table/serializers.py

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
from django.contrib.humanize.templatetags.humanize import naturaltime
77
from django.core.exceptions import ImproperlyConfigured
8-
from django.db.models import QuerySet
8+
from django.db.models import Model, QuerySet
99

1010
import asset_definitions
1111

@@ -78,10 +78,8 @@ def serialize(cls, **serialize_kwargs) -> SerializedTable:
7878
draw = int(filters.get("draw", draw))
7979

8080
# apply filtering, sorting and pagination (datatables)
81-
data = self.filter(data=data, fields=fields, filters=filters)
82-
data = self.sort(
83-
data=data, fields=fields, filters=filters, force_lower=cls._meta.force_lower
84-
)
81+
data = self.filter(data=data, filters=filters)
82+
data = self.sort(data=data, filters=filters)
8583
processed_data = []
8684
filtered_count = 0
8785

@@ -156,10 +154,15 @@ class TableSerializer(BaseTableSerializer):
156154
SerializedTable returns the in a format accepted by datatables.js
157155
"""
158156

159-
_meta: Type["TableSerializer.Meta"]
157+
_meta: Type[Any]
160158

161-
class Meta(BaseTableSerializer.Meta):
162-
model: Optional[str] = None
159+
class Meta:
160+
columns: Dict[str, str]
161+
order: List[str]
162+
title: Optional[str] = None
163+
first_as_absolute_url = False
164+
force_lower = True
165+
model: Optional[Model] = None
163166

164167
def __init_subclass__(cls, **kwargs):
165168
super().__init_subclass__(**kwargs)

requirements.txt

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,11 @@ decorator==5.1.1
6363
distlib==0.3.6
6464
# via virtualenv
6565
django==4.1.7
66-
# via model-bakery
66+
# via
67+
# django-asset-definitions
68+
# model-bakery
69+
django-asset-definitions==1.0.0
70+
# via -r requirements.in
6771
django-webtest==1.9.10
6872
# via -r requirements.in
6973
docutils==0.18.1
@@ -96,7 +100,7 @@ idna==3.4
96100
# via requests
97101
imagesize==1.4.1
98102
# via sphinx
99-
importlib-metadata==6.1.0
103+
importlib-metadata==6.8.0
100104
# via sphinx
101105
iniconfig==2.0.0
102106
# via pytest
@@ -291,6 +295,7 @@ urllib3==1.26.15
291295
# via requests
292296
vine==5.0.0
293297
# via
298+
# amqp
294299
# celery
295300
# kombu
296301
virtualenv==20.21.0
@@ -309,7 +314,7 @@ webtest==3.0.0
309314
# via django-webtest
310315
wheel==0.40.0
311316
# via pip-tools
312-
zipp==3.15.0
317+
zipp==3.16.2
313318
# via importlib-metadata
314319

315320
# The following packages are considered to be unsafe in a requirements file:

setup.cfg

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ python_requires = >=3.9
3030
install_requires =
3131
Django >= 3.2
3232
django-cors-headers
33+
django-asset-definitions
3334
pandas
3435
plotly
3536
plotly_express

0 commit comments

Comments
 (0)