From 2fcecff13ed9ed1d17f4f7ba5e0c11c02bd0408e Mon Sep 17 00:00:00 2001 From: Julien Date: Fri, 19 Apr 2024 09:14:55 +0200 Subject: [PATCH] doc: refactor example in dto factory, moving code to examples folder --- .../factory/enveloping_return_data_1.py | 10 ++ .../factory/enveloping_return_data_2.py | 6 + .../factory/enveloping_return_data_3.py | 16 +++ .../factory/excluding_fields_2.py | 9 ++ .../factory/paginated_return_data_1.py | 6 + .../factory/paginated_return_data_2.py | 19 +++ .../factory/response_return_data_1.py | 6 + .../factory/response_return_data_2.py | 14 +++ docs/usage/dto/1-abstract-dto.rst | 116 +++--------------- 9 files changed, 104 insertions(+), 98 deletions(-) create mode 100644 docs/examples/data_transfer_objects/factory/enveloping_return_data_1.py create mode 100644 docs/examples/data_transfer_objects/factory/enveloping_return_data_2.py create mode 100644 docs/examples/data_transfer_objects/factory/enveloping_return_data_3.py create mode 100644 docs/examples/data_transfer_objects/factory/excluding_fields_2.py create mode 100644 docs/examples/data_transfer_objects/factory/paginated_return_data_1.py create mode 100644 docs/examples/data_transfer_objects/factory/paginated_return_data_2.py create mode 100644 docs/examples/data_transfer_objects/factory/response_return_data_1.py create mode 100644 docs/examples/data_transfer_objects/factory/response_return_data_2.py diff --git a/docs/examples/data_transfer_objects/factory/enveloping_return_data_1.py b/docs/examples/data_transfer_objects/factory/enveloping_return_data_1.py new file mode 100644 index 0000000000..35e924d375 --- /dev/null +++ b/docs/examples/data_transfer_objects/factory/enveloping_return_data_1.py @@ -0,0 +1,10 @@ +from dataclasses import dataclass +from typing import Generic, TypeVar + +T = TypeVar("T") + + +@dataclass +class WithCount(Generic[T]): + count: int + data: List[T] \ No newline at end of file diff --git a/docs/examples/data_transfer_objects/factory/enveloping_return_data_2.py b/docs/examples/data_transfer_objects/factory/enveloping_return_data_2.py new file mode 100644 index 0000000000..62d6d58edd --- /dev/null +++ b/docs/examples/data_transfer_objects/factory/enveloping_return_data_2.py @@ -0,0 +1,6 @@ +from advanced_alchemy.dto import SQLAlchemyDTO +from litestar.dto import DTOConfig + + +class UserDTO(SQLAlchemyDTO[User]): + config = DTOConfig(exclude={"password", "created_at"}) \ No newline at end of file diff --git a/docs/examples/data_transfer_objects/factory/enveloping_return_data_3.py b/docs/examples/data_transfer_objects/factory/enveloping_return_data_3.py new file mode 100644 index 0000000000..eae9c7deb8 --- /dev/null +++ b/docs/examples/data_transfer_objects/factory/enveloping_return_data_3.py @@ -0,0 +1,16 @@ +from litestar import get + + +@get("/users", dto=UserDTO, sync_to_thread=False) +def get_users() -> WithCount[User]: + return WithCount( + count=1, + data=[ + User( + id=1, + name="Litestar User", + password="xyz", + created_at=datetime.now(), + ), + ], + ) \ No newline at end of file diff --git a/docs/examples/data_transfer_objects/factory/excluding_fields_2.py b/docs/examples/data_transfer_objects/factory/excluding_fields_2.py new file mode 100644 index 0000000000..e5e4929d0c --- /dev/null +++ b/docs/examples/data_transfer_objects/factory/excluding_fields_2.py @@ -0,0 +1,9 @@ +config = DTOConfig( + exclude={ + "id", + "address.id", + "address.street", + "pets.0.id", + "pets.0.user_id", + } +) \ No newline at end of file diff --git a/docs/examples/data_transfer_objects/factory/paginated_return_data_1.py b/docs/examples/data_transfer_objects/factory/paginated_return_data_1.py new file mode 100644 index 0000000000..62d6d58edd --- /dev/null +++ b/docs/examples/data_transfer_objects/factory/paginated_return_data_1.py @@ -0,0 +1,6 @@ +from advanced_alchemy.dto import SQLAlchemyDTO +from litestar.dto import DTOConfig + + +class UserDTO(SQLAlchemyDTO[User]): + config = DTOConfig(exclude={"password", "created_at"}) \ No newline at end of file diff --git a/docs/examples/data_transfer_objects/factory/paginated_return_data_2.py b/docs/examples/data_transfer_objects/factory/paginated_return_data_2.py new file mode 100644 index 0000000000..98d401d97d --- /dev/null +++ b/docs/examples/data_transfer_objects/factory/paginated_return_data_2.py @@ -0,0 +1,19 @@ +from litestar import get +from litestar.pagination import ClassicPagination + + +@get("/users", dto=UserDTO, sync_to_thread=False) +def get_users() -> ClassicPagination[User]: + return ClassicPagination( + page_size=10, + total_pages=1, + current_page=1, + items=[ + User( + id=1, + name="Litestar User", + password="xyz", + created_at=datetime.now(), + ), + ], + ) \ No newline at end of file diff --git a/docs/examples/data_transfer_objects/factory/response_return_data_1.py b/docs/examples/data_transfer_objects/factory/response_return_data_1.py new file mode 100644 index 0000000000..62d6d58edd --- /dev/null +++ b/docs/examples/data_transfer_objects/factory/response_return_data_1.py @@ -0,0 +1,6 @@ +from advanced_alchemy.dto import SQLAlchemyDTO +from litestar.dto import DTOConfig + + +class UserDTO(SQLAlchemyDTO[User]): + config = DTOConfig(exclude={"password", "created_at"}) \ No newline at end of file diff --git a/docs/examples/data_transfer_objects/factory/response_return_data_2.py b/docs/examples/data_transfer_objects/factory/response_return_data_2.py new file mode 100644 index 0000000000..ab954b28e9 --- /dev/null +++ b/docs/examples/data_transfer_objects/factory/response_return_data_2.py @@ -0,0 +1,14 @@ +from litestar import get, Response + + +@get("/users", dto=UserDTO, sync_to_thread=False) +def get_users() -> Response[User]: + return Response( + content=User( + id=1, + name="Litestar User", + password="xyz", + created_at=datetime.now(), + ), + headers={"X-Total-Count": "1"}, + ) \ No newline at end of file diff --git a/docs/usage/dto/1-abstract-dto.rst b/docs/usage/dto/1-abstract-dto.rst index 346141a573..eb71e5c4d4 100644 --- a/docs/usage/dto/1-abstract-dto.rst +++ b/docs/usage/dto/1-abstract-dto.rst @@ -73,17 +73,10 @@ nested models. Here, the config is created with the exclude parameter, which is a set of strings. Each string represents the path to a field in the ``User`` object that should be excluded from the output DTO. -.. code-block:: python - - config = DTOConfig( - exclude={ - "id", - "address.id", - "address.street", - "pets.0.id", - "pets.0.user_id", - } - ) +.. literalinclude:: /examples/data_transfer_objects/factory/excluding_fields_2.py + :caption: Excluding fields + :language: python + In this example, ``"id"`` represents the id field of the ``User`` object, ``"address.id"`` and ``"address.street"`` represent fields of the ``Address`` object nested inside the ``User`` object, and ``"pets.0.id"`` and @@ -288,53 +281,22 @@ attributes you might need. In this example, we have a ``WithCount`` dataclass wh The wrapper must be a python generic type with one or more type parameters, and at least one of those type parameters should describe an instance attribute that will be populated with the data. -.. code-block:: python - - from dataclasses import dataclass - from typing import Generic, TypeVar - - T = TypeVar("T") - - - @dataclass - class WithCount(Generic[T]): - count: int - data: List[T] +.. literalinclude:: /examples/data_transfer_objects/factory/enveloping_return_data_1.py + :language: python Now, create a DTO for your data object and configure it using ``DTOConfig``. In this example, we're excluding ``password`` and ``created_at`` from the final output. -.. code-block:: python - - from advanced_alchemy.dto import SQLAlchemyDTO - from litestar.dto import DTOConfig - +.. literalinclude:: /examples/data_transfer_objects/factory/enveloping_return_data_2.py + :language: python - class UserDTO(SQLAlchemyDTO[User]): - config = DTOConfig(exclude={"password", "created_at"}) Then, set up your route handler. This example sets up a ``/users`` endpoint, where a list of ``User`` objects is returned, wrapped in the ``WithCount`` dataclass. -.. code-block:: python - - from litestar import get - - - @get("/users", dto=UserDTO, sync_to_thread=False) - def get_users() -> WithCount[User]: - return WithCount( - count=1, - data=[ - User( - id=1, - name="Litestar User", - password="xyz", - created_at=datetime.now(), - ), - ], - ) +.. literalinclude:: /examples/data_transfer_objects/factory/enveloping_return_data_3.py + :language: python This setup allows the DTO to manage the rendering of ``User`` objects into the response. The DTO Factory type will find @@ -359,39 +321,16 @@ Litestar offers paginated response wrapper types, and DTO Factory types can hand The DTO is defined and configured, in our example, we're excluding ``password`` and ``created_at`` fields from the final representation of our users. -.. code-block:: python - - from advanced_alchemy.dto import SQLAlchemyDTO - from litestar.dto import DTOConfig - +.. literalinclude:: /examples/data_transfer_objects/factory/paginated_return_data_1.py + :language: python - class UserDTO(SQLAlchemyDTO[User]): - config = DTOConfig(exclude={"password", "created_at"}) The example sets up a ``/users`` endpoint, where a paginated list of ``User`` objects is returned, wrapped in :class:`ClassicPagination <.pagination.ClassicPagination>`. -.. code-block:: python - - from litestar import get - from litestar.pagination import ClassicPagination - +.. literalinclude:: /examples/data_transfer_objects/factory/paginated_return_data_2.py + :language: python - @get("/users", dto=UserDTO, sync_to_thread=False) - def get_users() -> ClassicPagination[User]: - return ClassicPagination( - page_size=10, - total_pages=1, - current_page=1, - items=[ - User( - id=1, - name="Litestar User", - password="xyz", - created_at=datetime.now(), - ), - ], - ) The :class:`ClassicPagination <.pagination.ClassicPagination>` class contains ``page_size`` (number of items per page), ``total_pages`` (total number of pages), ``current_page`` (current page number), and ``items`` (items for the current @@ -413,34 +352,15 @@ Litestar's DTO (Data Transfer Object) Factory Types can handle data wrapped in a We create a DTO for the ``User`` type and configure it using ``DTOConfig`` to exclude ``password`` and ``created_at`` from the serialized output. -.. code-block:: python - - from advanced_alchemy.dto import SQLAlchemyDTO - from litestar.dto import DTOConfig - - - class UserDTO(SQLAlchemyDTO[User]): - config = DTOConfig(exclude={"password", "created_at"}) +.. literalinclude:: /examples/data_transfer_objects/factory/response_return_data_1.py + :language: python The example sets up a ``/users`` endpoint where a ``User`` object is returned wrapped in a ``Response`` type. -.. code-block:: python - - from litestar import get, Response - +.. literalinclude:: /examples/data_transfer_objects/factory/response_return_data_2.py + :language: python - @get("/users", dto=UserDTO, sync_to_thread=False) - def get_users() -> Response[User]: - return Response( - content=User( - id=1, - name="Litestar User", - password="xyz", - created_at=datetime.now(), - ), - headers={"X-Total-Count": "1"}, - ) The ``Response`` object encapsulates the ``User`` object in its ``content`` attribute and allows us to configure the response received by the client. In this case, we add a custom header.