Skip to content

Commit

Permalink
Add support for dynamic serializer fields (#109)
Browse files Browse the repository at this point in the history
  • Loading branch information
melvinkcx authored Dec 23, 2024
1 parent 0d47d7b commit d58604f
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 5 deletions.
4 changes: 2 additions & 2 deletions drf_excel/renderers.py
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ def _check_validation_data(self, data):

def _serializer_fields(self, serializer, parent_key="", key_sep="."):
_fields_dict = {}
for k, v in serializer.get_fields().items():
for k, v in serializer.fields.items():
new_key = f"{parent_key}{key_sep}{k}" if parent_key else k
if isinstance(v, Serializer):
_fields_dict.update(self._serializer_fields(v, new_key, key_sep))
Expand Down Expand Up @@ -274,7 +274,7 @@ def _get_label(parent_label, label_sep, obj):
return False

_header_dict = {}
_fields = serializer.get_fields()
_fields = serializer.fields
for k, v in _fields.items():
new_key = f"{parent_key}{key_sep}{k}" if parent_key else k
# Skip headers we want to ignore
Expand Down
16 changes: 16 additions & 0 deletions tests/test_viewset_mixin.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,3 +110,19 @@ def test_secret_field_viewset(api_client, workbook_reader):
# Check that the secret field is not included in the header or data
assert [col.value for col in header] == ["title"]
assert [col.value for col in data] == ["foo"]


def test_dynamic_field_viewset(api_client, workbook_reader):
response = api_client.get("/dynamic-field/")
assert response.status_code == 200

wb = workbook_reader(response.content)
sheet = wb.worksheets[0]

header, data = list(sheet.rows)

header_values = [cell.value for cell in header]
assert header_values == ["field_1", "field_2", "field_99", "field_98"]

row_1_values = [cell.value for cell in data]
assert row_1_values == ["YUL", "CDG", "YYZ", "MAR"]
12 changes: 12 additions & 0 deletions tests/testapp/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,15 @@ class Meta:
fields = ("title", "secret", "secret_external")

extra_kwargs = {"secret": {"write_only": True}}


class DynamicFieldSerializer(serializers.Serializer):
field_1 = serializers.CharField()
field_2 = serializers.CharField()

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)

# Fields can be added dynamically
self.fields["field_99"] = serializers.CharField()
self.fields["field_98"] = serializers.CharField()
29 changes: 27 additions & 2 deletions tests/testapp/views.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
from rest_framework.viewsets import ReadOnlyModelViewSet
from rest_framework.response import Response
from rest_framework.viewsets import GenericViewSet, ReadOnlyModelViewSet

from drf_excel.mixins import XLSXFileMixin
from drf_excel.renderers import XLSXRenderer

from .models import AllFieldsModel, ExampleModel, SecretFieldModel
from .serializers import AllFieldsSerializer, ExampleSerializer, SecretFieldSerializer
from .serializers import (
AllFieldsSerializer,
DynamicFieldSerializer,
ExampleSerializer,
SecretFieldSerializer,
)


class ExampleViewSet(XLSXFileMixin, ReadOnlyModelViewSet):
Expand All @@ -26,3 +32,22 @@ class SecretFieldViewSet(XLSXFileMixin, ReadOnlyModelViewSet):
serializer_class = SecretFieldSerializer
renderer_classes = (XLSXRenderer,)
filename = "secret.xlsx"


class DynamicFieldViewSet(XLSXFileMixin, GenericViewSet):
serializer_class = DynamicFieldSerializer
renderer_classes = (XLSXRenderer,)
filename = "dynamic_field.xlsx"

def list(self, request, *args, **kwargs):
serializer = self.get_serializer(
data={
"field_1": "YUL",
"field_2": "CDG",
"field_55": "LHR",
"field_98": "MAR",
"field_99": "YYZ",
}
)
serializer.is_valid(raise_exception=True)
return Response(serializer.data)
8 changes: 7 additions & 1 deletion tests/urls.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
from rest_framework import routers

from .testapp.views import AllFieldsViewSet, ExampleViewSet, SecretFieldViewSet
from .testapp.views import (
AllFieldsViewSet,
DynamicFieldViewSet,
ExampleViewSet,
SecretFieldViewSet,
)

router = routers.SimpleRouter()
router.register(r"examples", ExampleViewSet)
router.register(r"all-fields", AllFieldsViewSet)
router.register(r"secret-field", SecretFieldViewSet)
router.register(r"dynamic-field", DynamicFieldViewSet, basename="dynamic-field")

urlpatterns = router.urls

0 comments on commit d58604f

Please sign in to comment.