diff --git a/django-stubs/db/models/fields/__init__.pyi b/django-stubs/db/models/fields/__init__.pyi index 631af5a..3dac311 100644 --- a/django-stubs/db/models/fields/__init__.pyi +++ b/django-stubs/db/models/fields/__init__.pyi @@ -43,6 +43,64 @@ _ST = TypeVar("_ST", contravariant=True) _GT = TypeVar("_GT", covariant=True) class Field(RegisterLookupMixin, Generic[_ST, _GT]): + """ + Typing model fields. + + How does this work? + Let's take a look at the self-contained example + (it is way easier than our django implementation, but has the same concept). + + To understand this example you need: + 1. Be familiar with descriptors: https://docs.python.org/3/howto/descriptor.html + 2. Follow our explanation bellow + + Let's start with defining our fake model class and fake integer field. + + .. code:: python + + from typing import Generic, Union + + class Model(object): + ... + + _SetType = Union[int, float] # You can assign ints and floats + _GetType = int # access type is always `int` + + class IntField(object): + def __get__(self, instance: Model, owner) -> _GetType: + ... + + def __set__(self, instance, value: _SetType) -> None: + ... + + Now, let's create our own example model, + this would be something like ``User`` in your own apps: + + .. code:: python + + class Example(Model): + count = IntField() + + And now, lets test that our reveal type works: + + .. code:: python + + example = Example() + reveal_type(example.count) + # Revealed type is "builtins.int" + + example.count = 1.5 # ok + example.count = 'a' + # Incompatible types in assignment + # (expression has type "str", variable has type "Union[int, float]") + + Notice, that this is not magic. This is how descriptors work with ``mypy``. + + We also need ``_pyi_private_set_type`` attributes + and friends to help inside our plugin. + It is required to enhance parts like ``filter`` queries. + """ + _pyi_private_set_type: Any _pyi_private_get_type: Any _pyi_lookup_exact_type: Any