@@ -340,6 +340,60 @@ def assert_zero_count(model_type: type[models.Model]) -> None:
340340```
341341
342342
343+ ### How to type a custom ` models.Field ` ?
344+
345+ > [ !NOTE]
346+ > This require type generic support, see <a href =" #i-cannot-use-queryset-or-manager-with-type-annotations " >this section</a > to enable it.
347+
348+
349+ Django ` models.Field ` (and subclasses) are generic types with two parameters:
350+ - ` _ST ` : type that can be used when setting a value
351+ - ` _GT ` : type that will be returned when getting a value
352+
353+ When you create a subclass, you have two options depending on how strict you want
354+ the type to be for consumers of your custom field.
355+
356+ 1 . Generic subclass:
357+
358+ ``` python
359+ from typing import TypeVar, reveal_type
360+ from django.db import models
361+
362+ _ST = TypeVar(" _ST" , contravariant = True )
363+ _GT = TypeVar(" _GT" , covariant = True )
364+
365+ class MyIntegerField (models .IntegerField[_ST , _GT ]):
366+ ...
367+
368+ class User (models .Model ):
369+ my_field = MyIntegerField()
370+
371+
372+ reveal_type(User().my_field) # N: Revealed type is "int"
373+ User().my_field = " 12" # OK (because Django IntegerField allows str and will try to coerce it)
374+ ```
375+
376+ 2 . Non-generic subclass (more strict):
377+
378+ ``` python
379+ from typing import reveal_type
380+ from django.db import models
381+
382+ # This is a non-generic subclass being very explicit
383+ # that it expects only int when setting values.
384+ class MyStrictIntegerField (models .IntegerField[int , int ]):
385+ ...
386+
387+ class User (models .Model ):
388+ my_field = MyStrictIntegerField()
389+
390+
391+ reveal_type(User().my_field) # N: Revealed type is "int"
392+ User().my_field = " 12" # E: Incompatible types in assignment (expression has type "str", variable has type "int")
393+ ```
394+
395+ See mypy section on [ generic classes subclasses] ( https://mypy.readthedocs.io/en/stable/generics.html#defining-subclasses-of-generic-classes ) .
396+
343397## Related projects
344398
345399- [ ` awesome-python-typing ` ] ( https://github.com/typeddjango/awesome-python-typing ) - Awesome list of all typing-related things in Python.
0 commit comments