1"""
2Type stubs for typed model fields.
3
4These stubs tell type checkers that field constructors return primitive types,
5enabling typed model definitions like:
6 name: str = types.CharField()
7
8At runtime, these are Field instances (descriptors), but type checkers see the primitives.
9
10The return type is conditional on allow_null:
11- allow_null=False (default) returns the primitive type (e.g., str)
12- allow_null=True returns the primitive type | None (e.g., str | None)
13"""
14
15from collections.abc import Callable, Sequence
16from datetime import date, datetime, time, timedelta
17from decimal import Decimal
18from json import JSONDecoder, JSONEncoder
19from typing import Any, Literal, overload
20from uuid import UUID
21from zoneinfo import ZoneInfo
22
23# Import manager types from runtime (will be Generic[T, QS] there)
24from plain.postgres.base import Model
25from plain.postgres.fields.related_managers import (
26 ManyToManyManager,
27 ReverseForeignKeyManager,
28)
29from plain.postgres.query import QuerySet
30
31# String fields
32@overload
33def CharField(
34 *,
35 max_length: int | None = None,
36 required: bool = True,
37 allow_null: Literal[True],
38 default: Any = ...,
39 choices: Any = None,
40 validators: Sequence[Callable[..., Any]] = (),
41 error_messages: dict[str, str] | None = None,
42) -> str | None: ...
43@overload
44def CharField(
45 *,
46 max_length: int | None = None,
47 required: bool = True,
48 allow_null: Literal[False] = False,
49 default: Any = ...,
50 choices: Any = None,
51 validators: Sequence[Callable[..., Any]] = (),
52 error_messages: dict[str, str] | None = None,
53) -> str: ...
54@overload
55def TextField(
56 *,
57 max_length: int | None = None,
58 required: bool = True,
59 allow_null: Literal[True],
60 default: Any = ...,
61 choices: Any = None,
62 validators: Sequence[Callable[..., Any]] = (),
63 error_messages: dict[str, str] | None = None,
64) -> str | None: ...
65@overload
66def TextField(
67 *,
68 max_length: int | None = None,
69 required: bool = True,
70 allow_null: Literal[False] = False,
71 default: Any = ...,
72 choices: Any = None,
73 validators: Sequence[Callable[..., Any]] = (),
74 error_messages: dict[str, str] | None = None,
75) -> str: ...
76@overload
77def EmailField(
78 *,
79 max_length: int | None = None,
80 required: bool = True,
81 allow_null: Literal[True],
82 default: Any = ...,
83 choices: Any = None,
84 validators: Sequence[Callable[..., Any]] = (),
85 error_messages: dict[str, str] | None = None,
86) -> str | None: ...
87@overload
88def EmailField(
89 *,
90 max_length: int | None = None,
91 required: bool = True,
92 allow_null: Literal[False] = False,
93 default: Any = ...,
94 choices: Any = None,
95 validators: Sequence[Callable[..., Any]] = (),
96 error_messages: dict[str, str] | None = None,
97) -> str: ...
98@overload
99def URLField(
100 *,
101 max_length: int | None = None,
102 required: bool = True,
103 allow_null: Literal[True],
104 default: Any = ...,
105 choices: Any = None,
106 validators: Sequence[Callable[..., Any]] = (),
107 error_messages: dict[str, str] | None = None,
108) -> str | None: ...
109@overload
110def URLField(
111 *,
112 max_length: int | None = None,
113 required: bool = True,
114 allow_null: Literal[False] = False,
115 default: Any = ...,
116 choices: Any = None,
117 validators: Sequence[Callable[..., Any]] = (),
118 error_messages: dict[str, str] | None = None,
119) -> str: ...
120
121# Integer fields
122@overload
123def IntegerField(
124 *,
125 max_length: int | None = None,
126 required: bool = True,
127 allow_null: Literal[True],
128 default: Any = ...,
129 choices: Any = None,
130 validators: Sequence[Callable[..., Any]] = (),
131 error_messages: dict[str, str] | None = None,
132) -> int | None: ...
133@overload
134def IntegerField(
135 *,
136 max_length: int | None = None,
137 required: bool = True,
138 allow_null: Literal[False] = False,
139 default: Any = ...,
140 choices: Any = None,
141 validators: Sequence[Callable[..., Any]] = (),
142 error_messages: dict[str, str] | None = None,
143) -> int: ...
144@overload
145def BigIntegerField(
146 *,
147 max_length: int | None = None,
148 required: bool = True,
149 allow_null: Literal[True],
150 default: Any = ...,
151 choices: Any = None,
152 validators: Sequence[Callable[..., Any]] = (),
153 error_messages: dict[str, str] | None = None,
154) -> int | None: ...
155@overload
156def BigIntegerField(
157 *,
158 max_length: int | None = None,
159 required: bool = True,
160 allow_null: Literal[False] = False,
161 default: Any = ...,
162 choices: Any = None,
163 validators: Sequence[Callable[..., Any]] = (),
164 error_messages: dict[str, str] | None = None,
165) -> int: ...
166@overload
167def SmallIntegerField(
168 *,
169 max_length: int | None = None,
170 required: bool = True,
171 allow_null: Literal[True],
172 default: Any = ...,
173 choices: Any = None,
174 validators: Sequence[Callable[..., Any]] = (),
175 error_messages: dict[str, str] | None = None,
176) -> int | None: ...
177@overload
178def SmallIntegerField(
179 *,
180 max_length: int | None = None,
181 required: bool = True,
182 allow_null: Literal[False] = False,
183 default: Any = ...,
184 choices: Any = None,
185 validators: Sequence[Callable[..., Any]] = (),
186 error_messages: dict[str, str] | None = None,
187) -> int: ...
188@overload
189def PositiveIntegerField(
190 *,
191 max_length: int | None = None,
192 required: bool = True,
193 allow_null: Literal[True],
194 default: Any = ...,
195 choices: Any = None,
196 validators: Sequence[Callable[..., Any]] = (),
197 error_messages: dict[str, str] | None = None,
198) -> int | None: ...
199@overload
200def PositiveIntegerField(
201 *,
202 max_length: int | None = None,
203 required: bool = True,
204 allow_null: Literal[False] = False,
205 default: Any = ...,
206 choices: Any = None,
207 validators: Sequence[Callable[..., Any]] = (),
208 error_messages: dict[str, str] | None = None,
209) -> int: ...
210@overload
211def PositiveBigIntegerField(
212 *,
213 max_length: int | None = None,
214 required: bool = True,
215 allow_null: Literal[True],
216 default: Any = ...,
217 choices: Any = None,
218 validators: Sequence[Callable[..., Any]] = (),
219 error_messages: dict[str, str] | None = None,
220) -> int | None: ...
221@overload
222def PositiveBigIntegerField(
223 *,
224 max_length: int | None = None,
225 required: bool = True,
226 allow_null: Literal[False] = False,
227 default: Any = ...,
228 choices: Any = None,
229 validators: Sequence[Callable[..., Any]] = (),
230 error_messages: dict[str, str] | None = None,
231) -> int: ...
232@overload
233def PositiveSmallIntegerField(
234 *,
235 max_length: int | None = None,
236 required: bool = True,
237 allow_null: Literal[True],
238 default: Any = ...,
239 choices: Any = None,
240 validators: Sequence[Callable[..., Any]] = (),
241 error_messages: dict[str, str] | None = None,
242) -> int | None: ...
243@overload
244def PositiveSmallIntegerField(
245 *,
246 max_length: int | None = None,
247 required: bool = True,
248 allow_null: Literal[False] = False,
249 default: Any = ...,
250 choices: Any = None,
251 validators: Sequence[Callable[..., Any]] = (),
252 error_messages: dict[str, str] | None = None,
253) -> int: ...
254@overload
255def PrimaryKeyField(
256 *,
257 max_length: int | None = None,
258 required: bool = True,
259 allow_null: Literal[True],
260 default: Any = ...,
261 choices: Any = None,
262 validators: Sequence[Callable[..., Any]] = (),
263 error_messages: dict[str, str] | None = None,
264) -> int | None: ...
265@overload
266def PrimaryKeyField(
267 *,
268 max_length: int | None = None,
269 required: bool = True,
270 allow_null: Literal[False] = False,
271 default: Any = ...,
272 choices: Any = None,
273 validators: Sequence[Callable[..., Any]] = (),
274 error_messages: dict[str, str] | None = None,
275) -> int: ...
276
277# Numeric fields
278@overload
279def FloatField(
280 *,
281 max_length: int | None = None,
282 required: bool = True,
283 allow_null: Literal[True],
284 default: Any = ...,
285 choices: Any = None,
286 validators: Sequence[Callable[..., Any]] = (),
287 error_messages: dict[str, str] | None = None,
288) -> float | None: ...
289@overload
290def FloatField(
291 *,
292 max_length: int | None = None,
293 required: bool = True,
294 allow_null: Literal[False] = False,
295 default: Any = ...,
296 choices: Any = None,
297 validators: Sequence[Callable[..., Any]] = (),
298 error_messages: dict[str, str] | None = None,
299) -> float: ...
300@overload
301def DecimalField(
302 *,
303 max_digits: int | None = None,
304 decimal_places: int | None = None,
305 max_length: int | None = None,
306 required: bool = True,
307 allow_null: Literal[True],
308 default: Any = ...,
309 choices: Any = None,
310 validators: Sequence[Callable[..., Any]] = (),
311 error_messages: dict[str, str] | None = None,
312) -> Decimal | None: ...
313@overload
314def DecimalField(
315 *,
316 max_digits: int | None = None,
317 decimal_places: int | None = None,
318 max_length: int | None = None,
319 required: bool = True,
320 allow_null: Literal[False] = False,
321 default: Any = ...,
322 choices: Any = None,
323 validators: Sequence[Callable[..., Any]] = (),
324 error_messages: dict[str, str] | None = None,
325) -> Decimal: ...
326
327# Boolean field
328@overload
329def BooleanField(
330 *,
331 max_length: int | None = None,
332 required: bool = True,
333 allow_null: Literal[True],
334 default: Any = ...,
335 choices: Any = None,
336 validators: Sequence[Callable[..., Any]] = (),
337 error_messages: dict[str, str] | None = None,
338) -> bool | None: ...
339@overload
340def BooleanField(
341 *,
342 max_length: int | None = None,
343 required: bool = True,
344 allow_null: Literal[False] = False,
345 default: Any = ...,
346 choices: Any = None,
347 validators: Sequence[Callable[..., Any]] = (),
348 error_messages: dict[str, str] | None = None,
349) -> bool: ...
350
351# Date/time fields
352@overload
353def DateField(
354 *,
355 auto_now: bool = False,
356 auto_now_add: bool = False,
357 max_length: int | None = None,
358 required: bool = True,
359 allow_null: Literal[True],
360 default: Any = ...,
361 choices: Any = None,
362 validators: Sequence[Callable[..., Any]] = (),
363 error_messages: dict[str, str] | None = None,
364) -> date | None: ...
365@overload
366def DateField(
367 *,
368 auto_now: bool = False,
369 auto_now_add: bool = False,
370 max_length: int | None = None,
371 required: bool = True,
372 allow_null: Literal[False] = False,
373 default: Any = ...,
374 choices: Any = None,
375 validators: Sequence[Callable[..., Any]] = (),
376 error_messages: dict[str, str] | None = None,
377) -> date: ...
378@overload
379def DateTimeField(
380 *,
381 auto_now: bool = False,
382 auto_now_add: bool = False,
383 max_length: int | None = None,
384 required: bool = True,
385 allow_null: Literal[True],
386 default: Any = ...,
387 choices: Any = None,
388 validators: Sequence[Callable[..., Any]] = (),
389 error_messages: dict[str, str] | None = None,
390) -> datetime | None: ...
391@overload
392def DateTimeField(
393 *,
394 auto_now: bool = False,
395 auto_now_add: bool = False,
396 max_length: int | None = None,
397 required: bool = True,
398 allow_null: Literal[False] = False,
399 default: Any = ...,
400 choices: Any = None,
401 validators: Sequence[Callable[..., Any]] = (),
402 error_messages: dict[str, str] | None = None,
403) -> datetime: ...
404@overload
405def TimeField(
406 *,
407 auto_now: bool = False,
408 auto_now_add: bool = False,
409 max_length: int | None = None,
410 required: bool = True,
411 allow_null: Literal[True],
412 default: Any = ...,
413 choices: Any = None,
414 validators: Sequence[Callable[..., Any]] = (),
415 error_messages: dict[str, str] | None = None,
416) -> time | None: ...
417@overload
418def TimeField(
419 *,
420 auto_now: bool = False,
421 auto_now_add: bool = False,
422 max_length: int | None = None,
423 required: bool = True,
424 allow_null: Literal[False] = False,
425 default: Any = ...,
426 choices: Any = None,
427 validators: Sequence[Callable[..., Any]] = (),
428 error_messages: dict[str, str] | None = None,
429) -> time: ...
430@overload
431def DurationField(
432 *,
433 max_length: int | None = None,
434 required: bool = True,
435 allow_null: Literal[True],
436 default: Any = ...,
437 choices: Any = None,
438 validators: Sequence[Callable[..., Any]] = (),
439 error_messages: dict[str, str] | None = None,
440) -> timedelta | None: ...
441@overload
442def DurationField(
443 *,
444 max_length: int | None = None,
445 required: bool = True,
446 allow_null: Literal[False] = False,
447 default: Any = ...,
448 choices: Any = None,
449 validators: Sequence[Callable[..., Any]] = (),
450 error_messages: dict[str, str] | None = None,
451) -> timedelta: ...
452@overload
453def TimeZoneField(
454 *,
455 max_length: int | None = None,
456 required: bool = True,
457 allow_null: Literal[True],
458 default: Any = ...,
459 choices: Any = None,
460 validators: Sequence[Callable[..., Any]] = (),
461 error_messages: dict[str, str] | None = None,
462) -> ZoneInfo | None: ...
463@overload
464def TimeZoneField(
465 *,
466 max_length: int | None = None,
467 required: bool = True,
468 allow_null: Literal[False] = False,
469 default: Any = ...,
470 choices: Any = None,
471 validators: Sequence[Callable[..., Any]] = (),
472 error_messages: dict[str, str] | None = None,
473) -> ZoneInfo: ...
474
475# Other fields
476@overload
477def UUIDField(
478 *,
479 max_length: int | None = None,
480 required: bool = True,
481 allow_null: Literal[True],
482 default: Any = ...,
483 choices: Any = None,
484 validators: Sequence[Callable[..., Any]] = (),
485 error_messages: dict[str, str] | None = None,
486) -> UUID | None: ...
487@overload
488def UUIDField(
489 *,
490 max_length: int | None = None,
491 required: bool = True,
492 allow_null: Literal[False] = False,
493 default: Any = ...,
494 choices: Any = None,
495 validators: Sequence[Callable[..., Any]] = (),
496 error_messages: dict[str, str] | None = None,
497) -> UUID: ...
498@overload
499def BinaryField(
500 *,
501 max_length: int | None = None,
502 required: bool = True,
503 allow_null: Literal[True],
504 default: Any = ...,
505 choices: Any = None,
506 validators: Sequence[Callable[..., Any]] = (),
507 error_messages: dict[str, str] | None = None,
508) -> bytes | None: ...
509@overload
510def BinaryField(
511 *,
512 max_length: int | None = None,
513 required: bool = True,
514 allow_null: Literal[False] = False,
515 default: Any = ...,
516 choices: Any = None,
517 validators: Sequence[Callable[..., Any]] = (),
518 error_messages: dict[str, str] | None = None,
519) -> bytes: ...
520@overload
521def GenericIPAddressField(
522 *,
523 protocol: str = "both",
524 unpack_ipv4: bool = False,
525 max_length: int | None = None,
526 required: bool = True,
527 allow_null: Literal[True],
528 default: Any = ...,
529 choices: Any = None,
530 validators: Sequence[Callable[..., Any]] = (),
531 error_messages: dict[str, str] | None = None,
532) -> str | None: ...
533@overload
534def GenericIPAddressField(
535 *,
536 protocol: str = "both",
537 unpack_ipv4: bool = False,
538 max_length: int | None = None,
539 required: bool = True,
540 allow_null: Literal[False] = False,
541 default: Any = ...,
542 choices: Any = None,
543 validators: Sequence[Callable[..., Any]] = (),
544 error_messages: dict[str, str] | None = None,
545) -> str: ...
546@overload
547def JSONField(
548 *,
549 encoder: type[JSONEncoder] | None = None,
550 decoder: type[JSONDecoder] | None = None,
551 max_length: int | None = None,
552 required: bool = True,
553 allow_null: Literal[True],
554 default: Any = ...,
555 choices: Any = None,
556 validators: Sequence[Callable[..., Any]] = (),
557 error_messages: dict[str, str] | None = None,
558) -> Any: ...
559@overload
560def JSONField(
561 *,
562 encoder: type[JSONEncoder] | None = None,
563 decoder: type[JSONDecoder] | None = None,
564 max_length: int | None = None,
565 required: bool = True,
566 allow_null: Literal[False] = False,
567 default: Any = ...,
568 choices: Any = None,
569 validators: Sequence[Callable[..., Any]] = (),
570 error_messages: dict[str, str] | None = None,
571) -> Any: ...
572
573# Encrypted fields
574@overload
575def EncryptedTextField(
576 *,
577 max_length: int | None = None,
578 required: bool = True,
579 allow_null: Literal[True],
580 default: Any = ...,
581 choices: Any = None,
582 validators: Sequence[Callable[..., Any]] = (),
583 error_messages: dict[str, str] | None = None,
584) -> str | None: ...
585@overload
586def EncryptedTextField(
587 *,
588 max_length: int | None = None,
589 required: bool = True,
590 allow_null: Literal[False] = False,
591 default: Any = ...,
592 choices: Any = None,
593 validators: Sequence[Callable[..., Any]] = (),
594 error_messages: dict[str, str] | None = None,
595) -> str: ...
596@overload
597def EncryptedJSONField(
598 *,
599 encoder: type[JSONEncoder] | None = None,
600 decoder: type[JSONDecoder] | None = None,
601 max_length: int | None = None,
602 required: bool = True,
603 allow_null: Literal[True],
604 default: Any = ...,
605 choices: Any = None,
606 validators: Sequence[Callable[..., Any]] = (),
607 error_messages: dict[str, str] | None = None,
608) -> Any: ...
609@overload
610def EncryptedJSONField(
611 *,
612 encoder: type[JSONEncoder] | None = None,
613 decoder: type[JSONDecoder] | None = None,
614 max_length: int | None = None,
615 required: bool = True,
616 allow_null: Literal[False] = False,
617 default: Any = ...,
618 choices: Any = None,
619 validators: Sequence[Callable[..., Any]] = (),
620 error_messages: dict[str, str] | None = None,
621) -> Any: ...
622
623# Related fields
624@overload
625def ForeignKeyField[T: Model](
626 to: type[T] | str,
627 on_delete: Any,
628 *,
629 related_query_name: str | None = None,
630 limit_choices_to: Any = None,
631 db_index: bool = True,
632 db_constraint: bool = True,
633 max_length: int | None = None,
634 required: bool = True,
635 allow_null: Literal[True],
636 default: Any = ...,
637 choices: Any = None,
638 validators: Sequence[Callable[..., Any]] = (),
639 error_messages: dict[str, str] | None = None,
640) -> T | None: ...
641@overload
642def ForeignKeyField[T: Model](
643 to: type[T] | str,
644 on_delete: Any,
645 *,
646 related_query_name: str | None = None,
647 limit_choices_to: Any = None,
648 db_index: bool = True,
649 db_constraint: bool = True,
650 max_length: int | None = None,
651 required: bool = True,
652 allow_null: Literal[False] = False,
653 default: Any = ...,
654 choices: Any = None,
655 validators: Sequence[Callable[..., Any]] = (),
656 error_messages: dict[str, str] | None = None,
657) -> T: ...
658def ManyToManyField[T: Model](
659 to: type[T] | str,
660 *,
661 through: Any,
662 through_fields: tuple[str, str] | None = None,
663 related_query_name: str | None = None,
664 limit_choices_to: Any = None,
665 symmetrical: bool | None = None,
666 max_length: int | None = None,
667 required: bool = True,
668 allow_null: bool = False,
669 default: Any = ...,
670 choices: Any = None,
671 validators: Sequence[Callable[..., Any]] = (),
672 error_messages: dict[str, str] | None = None,
673) -> ManyToManyManager[T]: ...
674
675# Reverse relation descriptors
676class ReverseForeignKey[T: Model, QS: QuerySet[Any] = QuerySet[Any]]:
677 """
678 Descriptor for the reverse side of a ForeignKeyField.
679
680 Type parameters:
681 _T: The related model type
682 _QS: The QuerySet type (use the model's custom QuerySet for proper method typing)
683
684 Example:
685 # With custom QuerySet for proper typing of custom methods like .enabled()
686 repos: ReverseForeignKey[Repo, RepoQuerySet] = ReverseForeignKey(to="Repo", field="organization")
687
688 # Usage: org.repos.query.enabled() # .enabled() is now recognized
689 """
690 def __init__(self, *, to: type[T] | str, field: str) -> None: ...
691 @overload
692 def __get__(self, instance: None, owner: type) -> ReverseForeignKey[T, QS]: ...
693 @overload
694 def __get__(
695 self, instance: Model, owner: type
696 ) -> ReverseForeignKeyManager[T, QS]: ...
697 def __get__(
698 self, instance: Model | None, owner: type
699 ) -> ReverseForeignKey[T, QS] | ReverseForeignKeyManager[T, QS]: ...
700
701class ReverseManyToMany[T: Model, QS: QuerySet[Any] = QuerySet[Any]]:
702 """
703 Descriptor for the reverse side of a ManyToManyField.
704
705 Type parameters:
706 _T: The related model type
707 _QS: The QuerySet type (use the model's custom QuerySet for proper method typing)
708 """
709 def __init__(self, *, to: type[T] | str, field: str) -> None: ...
710 @overload
711 def __get__(self, instance: None, owner: type) -> ReverseManyToMany[T, QS]: ...
712 @overload
713 def __get__(self, instance: Model, owner: type) -> ManyToManyManager[T, QS]: ...
714 def __get__(
715 self, instance: Model | None, owner: type
716 ) -> ReverseManyToMany[T, QS] | ManyToManyManager[T, QS]: ...
717
718# Export all types (should match types.py)
719__all__ = [
720 "BigIntegerField",
721 "BinaryField",
722 "BooleanField",
723 "CharField",
724 "DateField",
725 "DateTimeField",
726 "DecimalField",
727 "DurationField",
728 "EmailField",
729 "EncryptedJSONField",
730 "EncryptedTextField",
731 "FloatField",
732 "ForeignKeyField",
733 "GenericIPAddressField",
734 "IntegerField",
735 "JSONField",
736 "ManyToManyField",
737 "ManyToManyManager",
738 "PositiveBigIntegerField",
739 "PositiveIntegerField",
740 "PositiveSmallIntegerField",
741 "PrimaryKeyField",
742 "ReverseForeignKey",
743 "ReverseForeignKeyManager",
744 "ReverseManyToMany",
745 "SmallIntegerField",
746 "TextField",
747 "TimeField",
748 "TimeZoneField",
749 "URLField",
750 "UUIDField",
751]