Excluding from collections of nested models#
In Python, generic types can accept one or more type parameters (types that are enclosed in square brackets). This
pattern is often seen when representing a collection of some type, such as List[Person]
, where List
is a
generic container type, and Person
specializes the contents of the collection to contain only instances of the
Person
class.
Given a generic type, with an arbitrary number of type parameters (e.g., GenericType[Type0, Type1, ..., TypeN]
),
we use the index of the type parameter to indicate which type the exclusion should refer to. For example, a.0.b
,
excludes the b
field from the first type parameter of a
, a.1.b
excludes the b
field from the second type
parameter of a
, and so on.
To demonstrate, lets add a self-referencing children
relationship to our Person
model:
1from __future__ import annotations
2
3from dataclasses import dataclass
4
5from litestar import Litestar, get
6from litestar.dto import DataclassDTO, DTOConfig
7
8
9@dataclass
10class Address:
11 street: str
12 city: str
13 country: str
14
15
16@dataclass
17class Person:
18 name: str
19 age: int
20 email: str
21 address: Address
22 children: list[Person]
23
24
25class ReadDTO(DataclassDTO[Person]):
26 config = DTOConfig(exclude={"email", "address.street", "children.0.email", "children.0.address"})
27
28
29@get("/person/{name:str}", return_dto=ReadDTO, sync_to_thread=False)
30def get_person(name: str) -> Person:
31 # Your logic to retrieve the person goes here
32 # For demonstration purposes, a placeholder Person instance is returned
33 address = Address(street="123 Main St", city="Cityville", country="Countryland")
34 child1 = Person(name="Child1", age=10, email="child1@example.com", address=address, children=[])
35 child2 = Person(name="Child2", age=8, email="child2@example.com", address=address, children=[])
36 return Person(
37 name=name,
38 age=30,
39 email=f"email_of_{name}@example.com",
40 address=address,
41 children=[child1, child2],
42 )
43
44
45app = Litestar(route_handlers=[get_person])
Now, a Person
can have one or many children
, and each child
can have one or many children
, and so on.
We have explicitly excluded the email
and address
fields of all represented children
("children.0.email", "children.0.address"
).
In our handler we add children
to the Person
, and each child has no children
of their own.
Here’s the output:
Fantastic! Our children
are now represented in the output, and their emails and addresses are excluded. However,
astute readers may have noticed that we didn’t exclude the children
field of Person.children
(e.g., children.0.children
), yet that field is not represented in the output. To understand why, we’ll next look at
the max_nested_depth
configuration option.