Skip to content

Commit 2caeeda

Browse files
Kumzycofin
andauthored
docs: Add doc for creating a custom model (#333)
* docs: fix docs service for service with msgspec * docs: add example for creation custom model * docs: fix title * docs: clean up wording --------- Co-authored-by: Cody Fincher <[email protected]>
1 parent b194dc3 commit 2caeeda

File tree

2 files changed

+57
-2
lines changed

2 files changed

+57
-2
lines changed

docs/usage/modeling.rst

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,4 +242,59 @@ Here's how to use these models with the UniqueMixin:
242242
await session.flush()
243243
return post
244244
245+
246+
247+
Customizing Declarative Base
248+
-----------------------------
249+
250+
In case one of the built in declarative bases do not meet your needs (or you already have your own), Advanced Alchemy already supports customizing the ``DeclarativeBase`` class.
251+
252+
Here's an example showing a class to generate a server-side UUID primary key for `postgres`:
253+
254+
.. code-block:: python
255+
256+
from datetime import datetime
257+
from uuid import UUID, uuid4
258+
259+
from advanced_alchemy.base import CommonTableAttributes, orm_registry
260+
from sqlalchemy import text
261+
from sqlalchemy.orm import (
262+
DeclarativeBase,
263+
Mapped,
264+
declared_attr,
265+
mapped_column,
266+
orm_insert_sentinel,
267+
)
268+
269+
270+
class ServerSideUUIDPrimaryKey:
271+
"""UUID Primary Key Field Mixin."""
272+
273+
id: Mapped[UUID] = mapped_column(default=uuid4, primary_key=True, server_default=text("gen_random_uuid()"))
274+
"""UUID Primary key column."""
275+
276+
# noinspection PyMethodParameters
277+
@declared_attr
278+
def _sentinel(cls) -> Mapped[int]:
279+
"""Sentinel value required for SQLAlchemy bulk DML with UUIDs."""
280+
return orm_insert_sentinel(name="sa_orm_sentinel")
281+
282+
283+
class ServerSideUUIDBase(ServerSideUUIDPrimaryKey, CommonTableAttributes, DeclarativeBase):
284+
"""Base for all SQLAlchemy declarative models with the custom UUID primary key ."""
285+
286+
registry = orm_registry
287+
288+
289+
# Using ServerSideUUIDBase
290+
class User(ServerSideUUIDBase):
291+
"""User model with ServerSideUUIDBase."""
292+
293+
username: Mapped[str] = mapped_column(unique=True, index=True)
294+
email: Mapped[str] = mapped_column(unique=True)
295+
full_name: Mapped[str]
296+
is_active: Mapped[bool] = mapped_column(default=True)
297+
last_login: Mapped[datetime | None] = mapped_column(default=None)
298+
299+
245300
With this foundation in place, let's look at the repository pattern.

docs/usage/services.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -225,9 +225,9 @@ Services can handle complex business logic involving multiple repositories:
225225
226226
async def to_model(self, data: ModelDictT[Post], operation: str | None = None) -> Post:
227227
"""Convert a dictionary, Msgspec model, or Pydantic model to a Post model."""
228-
if (is_msgspec_model(data) or is_pydantic_model(data)) and operation == "create" and data.slug is None:
228+
if (is_msgspec_struct(data) or is_pydantic_model(data)) and operation == "create" and data.slug is None:
229229
data.slug = await self.repository.get_available_slug(data.name)
230-
if (is_msgspec_model(data) or is_pydantic_model(data)) and operation == "update" and data.slug is None:
230+
if (is_msgspec_struct(data) or is_pydantic_model(data)) and operation == "update" and data.slug is None:
231231
data.slug = await self.repository.get_available_slug(data.name)
232232
if is_dict(data) and "slug" not in data and operation == "create":
233233
data["slug"] = await self.repository.get_available_slug(data["name"])

0 commit comments

Comments
 (0)