Read only fields#
Sometimes, fields should never be able to be specified by the client. For example, upon creation of a new resource
instance, the id
field of a model should be generated by the server and not specified by the client.
1from __future__ import annotations
2
3from dataclasses import dataclass
4
5from litestar import Litestar, post
6from litestar.dto import DataclassDTO, DTOConfig
7
8
9@dataclass
10class Person:
11 name: str
12 age: int
13 email: str
14 id: int
15
16
17class ReadDTO(DataclassDTO[Person]):
18 config = DTOConfig(exclude={"email"})
19
20
21class WriteDTO(DataclassDTO[Person]):
22 config = DTOConfig(exclude={"id"})
23
24
25@post("/person", dto=WriteDTO, return_dto=ReadDTO, sync_to_thread=False)
26def create_person(data: Person) -> Person:
27 # Logic for persisting the person goes here
28 return data
29
30
31app = Litestar(route_handlers=[create_person])
In this adjustment, we add an id
field to the Person
model. We also create a new class, WriteDTO
that is
instructed to ignore the id
attribute.
The WriteDTO
class is assigned to the handler via the dto
kwarg (dto=WriteDTO
) meaning that the id
field
will be ignored from any data received from the client when creating a new Person
instance.
When we try to create a new Person
instance with an id
field specified, we get an error:
What’s happening? The DTO is trying to construct an instance of the Person
model but we have excluded the id
field from the accepted client data. The id
field is required by the Person
model, so the model constructor
raises an error.
There is more than one way to address this issue, for example we could assign a default value to the id
field and
overwrite the default in the handler, or we could create an entirely separate model that has no id
field, and
transfer the data from that to the Person
model in the handler. However, Litestar has a built-in solution for this:
DTOData
.