@@ -43,6 +43,64 @@ _ST = TypeVar("_ST", contravariant=True)
43
43
_GT = TypeVar ("_GT" , covariant = True )
44
44
45
45
class Field (RegisterLookupMixin , Generic [_ST , _GT ]):
46
+ """
47
+ Typing model fields.
48
+
49
+ How does this work?
50
+ Let's take a look at the self-contained example
51
+ (it is way easier than our django implementation, but has the same concept).
52
+
53
+ To understand this example you need:
54
+ 1. Be familiar with descriptors: https://docs.python.org/3/howto/descriptor.html
55
+ 2. Follow our explanation bellow
56
+
57
+ Let's start with defining our fake model class and fake integer field.
58
+
59
+ .. code:: python
60
+
61
+ from typing import Generic, Union
62
+
63
+ class Model(object):
64
+ ...
65
+
66
+ _SetType = Union[int, float] # You can assign ints and floats
67
+ _GetType = int # access type is always `int`
68
+
69
+ class IntField(object):
70
+ def __get__(self, instance: Model, owner) -> _GetType:
71
+ ...
72
+
73
+ def __set__(self, instance, value: _SetType) -> None:
74
+ ...
75
+
76
+ Now, let's create our own example model,
77
+ this would be something like ``User`` in your own apps:
78
+
79
+ .. code:: python
80
+
81
+ class Example(Model):
82
+ count = IntField()
83
+
84
+ And now, lets test that our reveal type works:
85
+
86
+ .. code:: python
87
+
88
+ example = Example()
89
+ reveal_type(example.count)
90
+ # Revealed type is "builtins.int"
91
+
92
+ example.count = 1.5 # ok
93
+ example.count = 'a'
94
+ # Incompatible types in assignment
95
+ # (expression has type "str", variable has type "Union[int, float]")
96
+
97
+ Notice, that this is not magic. This is how descriptors work with ``mypy``.
98
+
99
+ We also need ``_pyi_private_set_type`` attributes
100
+ and friends to help inside our plugin.
101
+ It is required to enhance parts like ``filter`` queries.
102
+ """
103
+
46
104
_pyi_private_set_type : Any
47
105
_pyi_private_get_type : Any
48
106
_pyi_lookup_exact_type : Any
0 commit comments