Skip to content

Commit 0ab00ce

Browse files
authored
Feat/support pydantic expansion in filters (#136)
* add tests for expanding pydantic models returned by filter lambdas * expand pydantic objects returned by filter lambdas * bumpversion and changelog
1 parent 3475f9d commit 0ab00ce

8 files changed

Lines changed: 27 additions & 6 deletions

File tree

.bumpversion.cfg

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[bumpversion]
2-
current_version = 0.31.2
2+
current_version = 0.31.3
33

44
[bumpversion:file:pyproject.toml]
55

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file.
44
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
55
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

7+
# [0.31.3] - 2023-09-30
8+
- [PR 136](https://github.com/salesforce/django-declarative-apis/pull/136) Fix filter expansion for pydantic objects
9+
10+
711
# [0.31.2 = 2023-09-11]
812
- [PR 134](https://github.com/salesforce/django-declarative-apis/pull/134) Make filter caching work for all datatypes
913
- [PR 131](https://github.com/salesforce/django-declarative-apis/pull/131) Support non-utf8 request body

django_declarative_apis/machinery/filtering.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import logging
1111
import types
1212

13+
import pydantic
1314
from django.conf import settings
1415
from django.core.exceptions import FieldDoesNotExist
1516
from django.db import models
@@ -171,7 +172,7 @@ def _get_filtered_field_value( # noqa: C901
171172

172173
# should this value be passed through the filters itself?
173174
if val.__class__ in filter_def or isinstance(
174-
val, (list, tuple, models.Model, models.query.QuerySet)
175+
val, (list, tuple, models.Model, models.query.QuerySet, pydantic.BaseModel)
175176
):
176177
val = _apply_filters_to_object(
177178
val, filter_def, expand_children, val.__class__, filter_cache, model_cache

docs/source/conf.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@
7474
# built documents.
7575

7676
# The full version, including alpha/beta/rc tags.
77-
release = '0.31.2' # set by bumpversion
77+
release = '0.31.3' # set by bumpversion
7878

7979
# The short X.Y version.
8080
version = release.rsplit('.', 1)[0]

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
44

55
[project]
66
name = "django-declarative-apis"
7-
version = "0.31.2" # set by bumpversion
7+
version = "0.31.3" # set by bumpversion
88
description = "Simple, readable, declarative APIs for Django"
99
readme = "README.md"
1010
dependencies = [

tests/filters.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,12 +49,14 @@
4949
models.InefficientLeaf: {"id": ALWAYS},
5050
models.InefficientBranchA: {"leaf": lambda inst: inst.leaf},
5151
models.InefficientBranchB: {"leaf": lambda inst: inst.leaf},
52+
models.PydanticBranch: {"id": ALWAYS},
5253
models.InefficientRoot: {"branch_a": ALWAYS, "branch_b": ALWAYS},
5354
models.InefficientPydanticRoot: {
5455
"default_factory": NEVER,
5556
"__len__": NEVER,
5657
"branch_a": lambda inst: inst.branch_a,
5758
"branch_b": lambda inst: inst.branch_b,
59+
"branch_p": lambda inst: inst.branch_p,
5860
},
5961
}
6062

tests/machinery/test_base.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -766,21 +766,26 @@ def setUp(self):
766766
leaf = models.InefficientLeaf.objects.create(id=1)
767767
branch_a = models.InefficientBranchA.objects.create(id=1, leaf=leaf)
768768
branch_b = models.InefficientBranchB.objects.create(id=1, leaf=leaf)
769+
branch_p = models.PydanticBranchChildClass(id=1)
769770
self.root = models.InefficientPydanticRoot(
770-
id=4, branch_a=branch_a, branch_b=branch_b
771+
id=4, branch_a=branch_a, branch_b=branch_b, branch_p=branch_p
771772
)
772773

773774
def test_filtering_accepts_nonhashable_root_item(self):
774775
with override_settings(
775776
DDA_FILTER_MODEL_CACHING_ENABLED=True, DDA_FILTER_CACHE_DEBUG_LOG=True
776777
):
777778
try:
778-
filtering.apply_filters_to_object(
779+
filtered = filtering.apply_filters_to_object(
779780
self.root, filters.INEFFICIENT_FUNCTION_FILTERS
780781
)
781782
except TypeError:
782783
self.fail("should be able to use filter caching on pydantic objects")
783784

785+
# make sure the pydantic child class was expanded
786+
self.assertIsInstance(filtered["branch_p"], dict)
787+
self.assertEqual(1, filtered["branch_p"]["id"])
788+
784789

785790
class ResourceUpdateEndpointDefinitionTestCase(
786791
testutils.RequestCreatorMixin, django.test.TestCase

tests/models.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,10 +73,19 @@ class InefficientRoot(models.Model):
7373
branch_b = models.ForeignKey(InefficientBranchB, on_delete=models.CASCADE)
7474

7575

76+
class PydanticBranch(pydantic.BaseModel):
77+
id: int = None
78+
79+
80+
class PydanticBranchChildClass(PydanticBranch):
81+
pass
82+
83+
7684
class InefficientPydanticRoot(pydantic.BaseModel, arbitrary_types_allowed=True):
7785
id: int = None
7886
branch_a: InefficientBranchA = None
7987
branch_b: InefficientBranchB = None
88+
branch_p: PydanticBranch = None
8089

8190

8291
try:

0 commit comments

Comments
 (0)