Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for dynamic serializer fields #109

Merged
merged 4 commits into from
Dec 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading