Skip to content

Commit d58604f

Browse files
authored
Add support for dynamic serializer fields (#109)
1 parent 0d47d7b commit d58604f

File tree

5 files changed

+64
-5
lines changed

5 files changed

+64
-5
lines changed

drf_excel/renderers.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ def _check_validation_data(self, data):
241241

242242
def _serializer_fields(self, serializer, parent_key="", key_sep="."):
243243
_fields_dict = {}
244-
for k, v in serializer.get_fields().items():
244+
for k, v in serializer.fields.items():
245245
new_key = f"{parent_key}{key_sep}{k}" if parent_key else k
246246
if isinstance(v, Serializer):
247247
_fields_dict.update(self._serializer_fields(v, new_key, key_sep))
@@ -274,7 +274,7 @@ def _get_label(parent_label, label_sep, obj):
274274
return False
275275

276276
_header_dict = {}
277-
_fields = serializer.get_fields()
277+
_fields = serializer.fields
278278
for k, v in _fields.items():
279279
new_key = f"{parent_key}{key_sep}{k}" if parent_key else k
280280
# Skip headers we want to ignore

tests/test_viewset_mixin.py

+16
Original file line numberDiff line numberDiff line change
@@ -110,3 +110,19 @@ def test_secret_field_viewset(api_client, workbook_reader):
110110
# Check that the secret field is not included in the header or data
111111
assert [col.value for col in header] == ["title"]
112112
assert [col.value for col in data] == ["foo"]
113+
114+
115+
def test_dynamic_field_viewset(api_client, workbook_reader):
116+
response = api_client.get("/dynamic-field/")
117+
assert response.status_code == 200
118+
119+
wb = workbook_reader(response.content)
120+
sheet = wb.worksheets[0]
121+
122+
header, data = list(sheet.rows)
123+
124+
header_values = [cell.value for cell in header]
125+
assert header_values == ["field_1", "field_2", "field_99", "field_98"]
126+
127+
row_1_values = [cell.value for cell in data]
128+
assert row_1_values == ["YUL", "CDG", "YYZ", "MAR"]

tests/testapp/serializers.py

+12
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,15 @@ class Meta:
3333
fields = ("title", "secret", "secret_external")
3434

3535
extra_kwargs = {"secret": {"write_only": True}}
36+
37+
38+
class DynamicFieldSerializer(serializers.Serializer):
39+
field_1 = serializers.CharField()
40+
field_2 = serializers.CharField()
41+
42+
def __init__(self, *args, **kwargs):
43+
super().__init__(*args, **kwargs)
44+
45+
# Fields can be added dynamically
46+
self.fields["field_99"] = serializers.CharField()
47+
self.fields["field_98"] = serializers.CharField()

tests/testapp/views.py

+27-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
1-
from rest_framework.viewsets import ReadOnlyModelViewSet
1+
from rest_framework.response import Response
2+
from rest_framework.viewsets import GenericViewSet, ReadOnlyModelViewSet
23

34
from drf_excel.mixins import XLSXFileMixin
45
from drf_excel.renderers import XLSXRenderer
56

67
from .models import AllFieldsModel, ExampleModel, SecretFieldModel
7-
from .serializers import AllFieldsSerializer, ExampleSerializer, SecretFieldSerializer
8+
from .serializers import (
9+
AllFieldsSerializer,
10+
DynamicFieldSerializer,
11+
ExampleSerializer,
12+
SecretFieldSerializer,
13+
)
814

915

1016
class ExampleViewSet(XLSXFileMixin, ReadOnlyModelViewSet):
@@ -26,3 +32,22 @@ class SecretFieldViewSet(XLSXFileMixin, ReadOnlyModelViewSet):
2632
serializer_class = SecretFieldSerializer
2733
renderer_classes = (XLSXRenderer,)
2834
filename = "secret.xlsx"
35+
36+
37+
class DynamicFieldViewSet(XLSXFileMixin, GenericViewSet):
38+
serializer_class = DynamicFieldSerializer
39+
renderer_classes = (XLSXRenderer,)
40+
filename = "dynamic_field.xlsx"
41+
42+
def list(self, request, *args, **kwargs):
43+
serializer = self.get_serializer(
44+
data={
45+
"field_1": "YUL",
46+
"field_2": "CDG",
47+
"field_55": "LHR",
48+
"field_98": "MAR",
49+
"field_99": "YYZ",
50+
}
51+
)
52+
serializer.is_valid(raise_exception=True)
53+
return Response(serializer.data)

tests/urls.py

+7-1
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
11
from rest_framework import routers
22

3-
from .testapp.views import AllFieldsViewSet, ExampleViewSet, SecretFieldViewSet
3+
from .testapp.views import (
4+
AllFieldsViewSet,
5+
DynamicFieldViewSet,
6+
ExampleViewSet,
7+
SecretFieldViewSet,
8+
)
49

510
router = routers.SimpleRouter()
611
router.register(r"examples", ExampleViewSet)
712
router.register(r"all-fields", AllFieldsViewSet)
813
router.register(r"secret-field", SecretFieldViewSet)
14+
router.register(r"dynamic-field", DynamicFieldViewSet, basename="dynamic-field")
915

1016
urlpatterns = router.urls

0 commit comments

Comments
 (0)