Skip to content

Commit 9dd6a91

Browse files
committed
Minor tweaks and updates version and release notes
1 parent 6531c5c commit 9dd6a91

File tree

6 files changed

+64
-32
lines changed

6 files changed

+64
-32
lines changed

README.md

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -486,7 +486,7 @@ Parameter names and wildcard values can be configured within a Django setting, n
486486
| Option | Description | Default |
487487
|-------------------------------|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------:|-----------------|
488488
| EXPAND_PARAM | The name of the parameter with the fields to be expanded | `"expand"` |
489-
| MAXIMUM_EXPANSION_DEPTH | The number of maximum depth permitted expansion | `None` |
489+
| MAXIMUM_EXPANSION_DEPTH | The max allowed expansion depth. By default it's unlimited. Expanding `state.towns` would equal a depth of 2 | `None` |
490490
| FIELDS_PARAM | The name of the parameter with the fields to be included (others will be omitted) | `"fields"` |
491491
| OMIT_PARAM | The name of the parameter with the fields to be omitted | `"omit"` |
492492
| RECURSIVE_EXPANSION_PERMITTED | If `False`, an exception is raised when a recursive pattern is found | `True` |
@@ -498,13 +498,13 @@ For example, if you want your API to work a bit more like [JSON API](https://jso
498498
REST_FLEX_FIELDS = {"EXPAND_PARAM": "include"}
499499
```
500500

501-
### Defining expansion and recursive limits at serializer level
501+
### Defining Expansion and Recursive Limits on Serializer Classes
502502

503-
`maximum_expansion_depth` property can be overridden at serializer level. It can be configured as `int` or `None`.
503+
A `maximum_expansion_depth` integer property can be set on a serializer class.
504504

505-
`recursive_expansion_permitted` property can be overridden at serializer level. It must be `bool`.
505+
`recursive_expansion_permitted` boolean property can be set on a serializer class.
506506

507-
Both settings raise `serializers.ValidationError` when conditions are met but exceptions can be overridden in `_recursive_expansion_found` and `_expansion_depth_exceeded` methods.
507+
Both settings raise `serializers.ValidationError` when conditions are met but exceptions can be customized by overriding the `recursive_expansion_not_permitted` and `expansion_depth_exceeded` methods.
508508

509509

510510
## Serializer Introspection
@@ -584,6 +584,10 @@ It will automatically call `select_related` and `prefetch_related` on the curren
584584

585585
# Changelog <a id="changelog"></a>
586586

587+
## 1.0.2 (March 2023)
588+
589+
- Adds control over whether recursive expansions are allowed and allows setting the max expansion depth. Thanks @andruten!
590+
587591
## 1.0.1 (March 2023)
588592

589593
- Various bug fixes. Thanks @michaelschem, @andruten, and @erielias!

rest_flex_fields/__init__.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@
66
FIELDS_PARAM = FLEX_FIELDS_OPTIONS.get("FIELDS_PARAM", "fields")
77
OMIT_PARAM = FLEX_FIELDS_OPTIONS.get("OMIT_PARAM", "omit")
88
MAXIMUM_EXPANSION_DEPTH = FLEX_FIELDS_OPTIONS.get("MAXIMUM_EXPANSION_DEPTH", None)
9-
RECURSIVE_EXPANSION_PERMITTED = FLEX_FIELDS_OPTIONS.get("RECURSIVE_EXPANSION_PERMITTED", True)
9+
RECURSIVE_EXPANSION_PERMITTED = FLEX_FIELDS_OPTIONS.get(
10+
"RECURSIVE_EXPANSION_PERMITTED", True
11+
)
1012

1113
WILDCARD_ALL = "~all"
1214
WILDCARD_ASTERISK = "*"

rest_flex_fields/serializers.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,15 @@
22
import importlib
33
from typing import List, Optional, Tuple
44

5-
from django.conf import settings
65
from rest_framework import serializers
76

87
from rest_flex_fields import (
98
EXPAND_PARAM,
109
FIELDS_PARAM,
1110
OMIT_PARAM,
1211
WILDCARD_VALUES,
12+
MAXIMUM_EXPANSION_DEPTH,
13+
RECURSIVE_EXPANSION_PERMITTED,
1314
split_levels,
1415
)
1516

@@ -65,7 +66,7 @@ def get_maximum_expansion_depth(self) -> Optional[int]:
6566
"""
6667
Defined at serializer level or based on MAXIMUM_EXPANSION_DEPTH setting
6768
"""
68-
return self.maximum_expansion_depth or settings.REST_FLEX_FIELDS.get("MAXIMUM_EXPANSION_DEPTH", None)
69+
return self.maximum_expansion_depth or MAXIMUM_EXPANSION_DEPTH
6970

7071
def get_recursive_expansion_permitted(self) -> bool:
7172
"""
@@ -74,7 +75,7 @@ def get_recursive_expansion_permitted(self) -> bool:
7475
if self.recursive_expansion_permitted is not None:
7576
return self.recursive_expansion_permitted
7677
else:
77-
return settings.REST_FLEX_FIELDS.get("RECURSIVE_EXPANSION_PERMITTED", True)
78+
return RECURSIVE_EXPANSION_PERMITTED
7879

7980
def to_representation(self, instance):
8081
if not self._flex_fields_rep_applied:
@@ -280,19 +281,19 @@ def _get_query_param_value(self, field: str) -> List[str]:
280281
values = self.context["request"].query_params.getlist(field)
281282

282283
if not values:
283-
values = self.context["request"].query_params.getlist("{}[]".format(field))
284+
values = self.context["request"].query_params.getlist(f"{field}[]")
285+
286+
if values and len(values) == 1:
287+
values = values[0].split(",")
284288

285289
for expand_path in values:
286290
self._validate_recursive_expansion(expand_path)
287291
self._validate_expansion_depth(expand_path)
288292

289-
if values and len(values) == 1:
290-
return values[0].split(",")
291-
292293
return values or []
293294

294295
def _split_expand_field(self, expand_path: str) -> List[str]:
295-
return expand_path.split('.')
296+
return expand_path.split(".")
296297

297298
def recursive_expansion_not_permitted(self):
298299
"""

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ def readme():
2424
]
2525
setup(
2626
name="drf-flex-fields",
27-
version="1.0.1",
27+
version="1.0.2",
2828
description="Flexible, dynamic fields and nested resources for Django REST Framework serializers.",
2929
author="Robert Singer",
3030
author_email="[email protected]",

tests/settings.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -88,9 +88,15 @@
8888
{
8989
"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
9090
},
91-
{"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",},
92-
{"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",},
93-
{"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",},
91+
{
92+
"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
93+
},
94+
{
95+
"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
96+
},
97+
{
98+
"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
99+
},
94100
]
95101

96102

@@ -120,4 +126,4 @@
120126
# of `AutoField`. To avoid introducing migrations and silence the configuration warnings,
121127
# we're setting this to `AutoField`, which is ok for this use case (tests).
122128
# Reference: https://docs.djangoproject.com/en/3.2/releases/3.2/#customizing-type-of-auto-created-primary-keys
123-
DEFAULT_AUTO_FIELD = 'django.db.models.AutoField'
129+
DEFAULT_AUTO_FIELD = "django.db.models.AutoField"

tests/test_flex_fields_model_serializer.py

Lines changed: 32 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -185,26 +185,33 @@ def test_import_serializer_class(self):
185185
def test_make_expanded_field_serializer(self):
186186
pass
187187

188-
@override_settings(REST_FLEX_FIELDS={"RECURSIVE_EXPANSION_PERMITTED": False})
188+
@patch("rest_flex_fields.serializers.RECURSIVE_EXPANSION_PERMITTED", False)
189189
def test_recursive_expansion(self):
190190
with self.assertRaises(serializers.ValidationError):
191191
FlexFieldsModelSerializer(
192192
context={
193193
"request": MockRequest(
194-
method="GET", query_params=MultiValueDict({"expand": ["dog.leg.dog"]})
194+
method="GET",
195+
query_params=MultiValueDict({"expand": ["dog.leg.dog"]}),
195196
)
196197
}
197198
)
198199

199-
@patch('rest_flex_fields.FlexFieldsModelSerializer.recursive_expansion_permitted', new_callable=PropertyMock)
200-
def test_recursive_expansion_serializer_level(self, mock_recursive_expansion_permitted):
200+
@patch(
201+
"rest_flex_fields.FlexFieldsModelSerializer.recursive_expansion_permitted",
202+
new_callable=PropertyMock,
203+
)
204+
def test_recursive_expansion_serializer_level(
205+
self, mock_recursive_expansion_permitted
206+
):
201207
mock_recursive_expansion_permitted.return_value = False
202208

203209
with self.assertRaises(serializers.ValidationError):
204210
FlexFieldsModelSerializer(
205211
context={
206212
"request": MockRequest(
207-
method="GET", query_params=MultiValueDict({"expand": ["dog.leg.dog"]})
213+
method="GET",
214+
query_params=MultiValueDict({"expand": ["dog.leg.dog"]}),
208215
)
209216
}
210217
)
@@ -214,43 +221,55 @@ def test_expansion_depth(self):
214221
serializer = FlexFieldsModelSerializer(
215222
context={
216223
"request": MockRequest(
217-
method="GET", query_params=MultiValueDict({"expand": ["dog.leg.paws"]})
224+
method="GET",
225+
query_params=MultiValueDict({"expand": ["dog.leg.paws"]}),
218226
)
219227
}
220228
)
221229
self.assertEqual(serializer._flex_options_all["expand"], ["dog.leg.paws"])
222230

223-
@override_settings(REST_FLEX_FIELDS={"MAXIMUM_EXPANSION_DEPTH": 2})
231+
@patch("rest_flex_fields.serializers.MAXIMUM_EXPANSION_DEPTH", 2)
224232
def test_expansion_depth_exception(self):
225233
with self.assertRaises(serializers.ValidationError):
226234
FlexFieldsModelSerializer(
227235
context={
228236
"request": MockRequest(
229-
method="GET", query_params=MultiValueDict({"expand": ["dog.leg.paws"]})
237+
method="GET",
238+
query_params=MultiValueDict({"expand": ["dog.leg.paws"]}),
230239
)
231240
}
232241
)
233242

234-
@patch('rest_flex_fields.FlexFieldsModelSerializer.maximum_expansion_depth', new_callable=PropertyMock)
243+
@patch(
244+
"rest_flex_fields.FlexFieldsModelSerializer.maximum_expansion_depth",
245+
new_callable=PropertyMock,
246+
)
235247
def test_expansion_depth_serializer_level(self, mock_maximum_expansion_depth):
236248
mock_maximum_expansion_depth.return_value = 3
237249
serializer = FlexFieldsModelSerializer(
238250
context={
239251
"request": MockRequest(
240-
method="GET", query_params=MultiValueDict({"expand": ["dog.leg.paws"]})
252+
method="GET",
253+
query_params=MultiValueDict({"expand": ["dog.leg.paws"]}),
241254
)
242255
}
243256
)
244257
self.assertEqual(serializer._flex_options_all["expand"], ["dog.leg.paws"])
245258

246-
@patch('rest_flex_fields.FlexFieldsModelSerializer.maximum_expansion_depth', new_callable=PropertyMock)
247-
def test_expansion_depth_serializer_level_exception(self, mock_maximum_expansion_depth):
259+
@patch(
260+
"rest_flex_fields.FlexFieldsModelSerializer.maximum_expansion_depth",
261+
new_callable=PropertyMock,
262+
)
263+
def test_expansion_depth_serializer_level_exception(
264+
self, mock_maximum_expansion_depth
265+
):
248266
mock_maximum_expansion_depth.return_value = 2
249267
with self.assertRaises(serializers.ValidationError):
250268
FlexFieldsModelSerializer(
251269
context={
252270
"request": MockRequest(
253-
method="GET", query_params=MultiValueDict({"expand": ["dog.leg.paws"]})
271+
method="GET",
272+
query_params=MultiValueDict({"expand": ["dog.leg.paws"]}),
254273
)
255274
}
256275
)

0 commit comments

Comments
 (0)