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