From 1c4c3ee70588f544ed59a5f90d52d2c8c7c5ad39 Mon Sep 17 00:00:00 2001 From: melvin Date: Fri, 20 Dec 2024 16:14:01 -0500 Subject: [PATCH 1/4] replace serializer.get_field() with serializer.fields --- drf_excel/renderers.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drf_excel/renderers.py b/drf_excel/renderers.py index ba29313..1916a5a 100644 --- a/drf_excel/renderers.py +++ b/drf_excel/renderers.py @@ -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)) @@ -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 @@ -349,7 +349,7 @@ def _make_body(self, body, row, row_count): if "row_color" in row: last_letter = get_column_letter(column_count) - cell_range = self.ws[f"A{row_count}" : f"{last_letter}{row_count}"] + cell_range = self.ws[f"A{row_count}": f"{last_letter}{row_count}"] fill = PatternFill(fill_type="solid", start_color=row["row_color"]) for r in cell_range: @@ -372,7 +372,7 @@ def _drf_to_xlsx_field(self, key, value) -> XLSXField: "style": self.body_style, # Basically using formatter of custom col as a custom mapping "mapping": self.custom_cols.get(key, {}).get("formatter") - or self.custom_mappings.get(key), + or self.custom_mappings.get(key), "cell_style": cell_style, } From de58ec6993104687d400fdbef16e36015b3e4aa7 Mon Sep 17 00:00:00 2001 From: melvin Date: Fri, 20 Dec 2024 16:16:22 -0500 Subject: [PATCH 2/4] remove format change --- drf_excel/renderers.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drf_excel/renderers.py b/drf_excel/renderers.py index 1916a5a..002d7ba 100644 --- a/drf_excel/renderers.py +++ b/drf_excel/renderers.py @@ -349,7 +349,7 @@ def _make_body(self, body, row, row_count): if "row_color" in row: last_letter = get_column_letter(column_count) - cell_range = self.ws[f"A{row_count}": f"{last_letter}{row_count}"] + cell_range = self.ws[f"A{row_count}" : f"{last_letter}{row_count}"] fill = PatternFill(fill_type="solid", start_color=row["row_color"]) for r in cell_range: @@ -372,7 +372,7 @@ def _drf_to_xlsx_field(self, key, value) -> XLSXField: "style": self.body_style, # Basically using formatter of custom col as a custom mapping "mapping": self.custom_cols.get(key, {}).get("formatter") - or self.custom_mappings.get(key), + or self.custom_mappings.get(key), "cell_style": cell_style, } From d3c01d57389f4dd0f100d0a2dc0a0b95a733f868 Mon Sep 17 00:00:00 2001 From: melvin Date: Fri, 20 Dec 2024 19:49:04 -0500 Subject: [PATCH 3/4] add test cases --- tests/test_viewset_mixin.py | 16 ++++++++++++++++ tests/testapp/serializers.py | 12 ++++++++++++ tests/testapp/views.py | 30 +++++++++++++++++++++++++++--- tests/urls.py | 8 +++++++- 4 files changed, 62 insertions(+), 4 deletions(-) diff --git a/tests/test_viewset_mixin.py b/tests/test_viewset_mixin.py index 7799258..31b2911 100644 --- a/tests/test_viewset_mixin.py +++ b/tests/test_viewset_mixin.py @@ -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"] diff --git a/tests/testapp/serializers.py b/tests/testapp/serializers.py index e433822..e3f70b6 100644 --- a/tests/testapp/serializers.py +++ b/tests/testapp/serializers.py @@ -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() diff --git a/tests/testapp/views.py b/tests/testapp/views.py index 71b7038..69aa3f1 100644 --- a/tests/testapp/views.py +++ b/tests/testapp/views.py @@ -1,10 +1,15 @@ -from rest_framework.viewsets import ReadOnlyModelViewSet +from rest_framework.response import Response +from rest_framework.viewsets import ReadOnlyModelViewSet, ViewSet, GenericViewSet 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, + ExampleSerializer, + SecretFieldSerializer, + DynamicFieldSerializer, +) class ExampleViewSet(XLSXFileMixin, ReadOnlyModelViewSet): @@ -26,3 +31,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) diff --git a/tests/urls.py b/tests/urls.py index d875c66..538b043 100644 --- a/tests/urls.py +++ b/tests/urls.py @@ -1,10 +1,16 @@ from rest_framework import routers -from .testapp.views import AllFieldsViewSet, ExampleViewSet, SecretFieldViewSet +from .testapp.views import ( + AllFieldsViewSet, + ExampleViewSet, + SecretFieldViewSet, + DynamicFieldViewSet, +) 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 From 74906d2f7e6ebc5a1f4cc0ee5cc173b9bed5fdae Mon Sep 17 00:00:00 2001 From: melvin Date: Fri, 20 Dec 2024 20:06:52 -0500 Subject: [PATCH 4/4] delint --- tests/testapp/views.py | 5 +++-- tests/urls.py | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/testapp/views.py b/tests/testapp/views.py index 69aa3f1..77c43a8 100644 --- a/tests/testapp/views.py +++ b/tests/testapp/views.py @@ -1,14 +1,15 @@ from rest_framework.response import Response -from rest_framework.viewsets import ReadOnlyModelViewSet, ViewSet, GenericViewSet +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, + DynamicFieldSerializer, ExampleSerializer, SecretFieldSerializer, - DynamicFieldSerializer, ) diff --git a/tests/urls.py b/tests/urls.py index 538b043..8eadca0 100644 --- a/tests/urls.py +++ b/tests/urls.py @@ -2,9 +2,9 @@ from .testapp.views import ( AllFieldsViewSet, + DynamicFieldViewSet, ExampleViewSet, SecretFieldViewSet, - DynamicFieldViewSet, ) router = routers.SimpleRouter()