Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ Added
- ``QuerySet.contains()`` method to check if an object exists in a queryset.
- Added comprehensive EXPLAIN support for MySQL and PostgreSQL.
- Built-in ``DomainNameValidator``, ``URLValidator``, and ``EmailValidator`` classes for common validation patterns. (#2162)
- Typed ``**kwargs`` on field constructors via PEP 692 (``Unpack[TypedDict]``), so IDEs and type checkers can autocomplete and validate common field arguments (``default``, ``null``, ``unique``, ``db_index``, ``description``, etc.). (#2168)

Fixed
^^^^^
Expand Down
72 changes: 71 additions & 1 deletion tortoise/fields/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from collections.abc import Callable
from enum import Enum
from functools import reduce
from typing import TYPE_CHECKING, Any, Generic, TypeVar, overload
from typing import TYPE_CHECKING, Any, Generic, TypedDict, TypeVar, overload

from pypika_tortoise.terms import Term

Expand Down Expand Up @@ -90,6 +90,76 @@ class OnDelete(StrEnum):
NO_ACTION = OnDelete.NO_ACTION


class _FieldKwargsCommon(TypedDict, total=False):
""":class:`Field` constructor arguments that are never declared as explicit parameters.

Used with :data:`typing.Unpack` to give ``**kwargs`` explicit type hints. This is the
smallest set; fields that declare ``unique``/``db_index``/``primary_key`` explicitly
(e.g. ``TextField``) unpack this directly to avoid PEP 692 parameter-name collisions.
"""

source_field: str | None
generated: bool
default: Any
db_default: Any
description: str | None
model: Model | None
validators: list[Validator | Callable]
pk: bool # deprecated alias for primary_key
index: bool # deprecated alias for db_index


class _FieldKwargsNoPk(_FieldKwargsCommon, total=False):
"""Common arguments excluding ``primary_key`` and ``null``.

For constructors that declare ``primary_key`` and ``null`` as explicit parameters
(e.g. ``IntField``).
"""

unique: bool
db_index: bool | None


class FieldKwargs(_FieldKwargsNoPk, total=False):
"""Common arguments excluding ``null``.

For constructors that declare only ``null`` as an explicit parameter (the majority).
"""

primary_key: bool | None


class JSONFieldKwargs(FieldKwargs, total=False):
"""Constructor arguments for :class:`JSONField`.

``JSONField`` declares neither ``null`` nor ``primary_key`` explicitly, and also accepts
a custom ``field_type`` (e.g. a Pydantic model class).
"""

null: bool
field_type: Any


class RelationalFieldKwargs(FieldKwargs, total=False):
"""Constructor arguments for :func:`ForeignKeyField` and :func:`OneToOneField`.

Extends the common :class:`~tortoise.fields.base.FieldKwargs` with ``to_field``.
``null`` is declared as an explicit parameter on those constructors, so it is omitted.
"""

to_field: str | None


class ManyToManyFieldKwargs(_FieldKwargsCommon, total=False):
"""Constructor arguments for :func:`ManyToManyField`.

``unique`` is declared as an explicit parameter, so it is omitted here; the deprecated
``create_unique_index`` alias is still accepted.
"""

create_unique_index: bool # deprecated alias for unique


class _FieldMeta(type):
# TODO: Require functions to return field instances instead of this hack
def __new__(mcs, name: str, bases: tuple[type, ...], attrs: dict) -> type:
Expand Down
Loading
Loading