1from __future__ import annotations
   2
   3import collections.abc
   4import copy
   5import datetime
   6import decimal
   7import enum
   8import operator
   9import uuid
  10import warnings
  11from base64 import b64decode, b64encode
  12from collections.abc import Callable, Sequence
  13from functools import cached_property
  14from typing import (
  15    TYPE_CHECKING,
  16    Any,
  17    Generic,
  18    Protocol,
  19    Self,
  20    TypedDict,
  21    TypeVar,
  22    cast,
  23    overload,
  24)
  25
  26import psycopg
  27
  28from plain import exceptions, validators
  29from plain.models.constants import LOOKUP_SEP
  30from plain.models.enums import ChoicesMeta
  31from plain.models.postgres.sql import (
  32    CAST_CHAR_FIELD_WITHOUT_MAX_LENGTH,
  33    CAST_DATA_TYPES,
  34    DATA_TYPE_CHECK_CONSTRAINTS,
  35    DATA_TYPES,
  36    DATA_TYPES_SUFFIX,
  37    INTEGER_FIELD_RANGES,
  38    adapt_integerfield_value,
  39    adapt_ipaddressfield_value,
  40    quote_name,
  41)
  42from plain.models.query_utils import RegisterLookupMixin
  43from plain.preflight import PreflightResult
  44from plain.utils import timezone
  45from plain.utils.datastructures import DictWrapper
  46from plain.utils.dateparse import (
  47    parse_date,
  48    parse_datetime,
  49    parse_duration,
  50    parse_time,
  51)
  52from plain.utils.duration import duration_string
  53from plain.utils.functional import Promise
  54from plain.utils.ipv6 import clean_ipv6_address
  55from plain.utils.itercompat import is_iterable
  56
  57from ..registry import models_registry
  58
  59if TYPE_CHECKING:
  60    from plain.models.base import Model
  61    from plain.models.expressions import Col
  62    from plain.models.fields.reverse_related import ForeignObjectRel
  63    from plain.models.postgres.wrapper import DatabaseWrapper
  64    from plain.models.sql.compiler import SQLCompiler
  65
  66
  67class DbParameters(TypedDict, total=False):
  68    """Return type for Field.db_parameters()."""
  69
  70    type: str | None
  71    check: str | None
  72
  73
  74__all__ = [
  75    "BLANK_CHOICE_DASH",
  76    "DbParameters",
  77    "PrimaryKeyField",
  78    "BigIntegerField",
  79    "BinaryField",
  80    "BooleanField",
  81    "CharField",
  82    "DateField",
  83    "DateTimeField",
  84    "DecimalField",
  85    "DurationField",
  86    "EmailField",
  87    "Empty",
  88    "Field",
  89    "FloatField",
  90    "GenericIPAddressField",
  91    "IntegerField",
  92    "NOT_PROVIDED",
  93    "PositiveBigIntegerField",
  94    "PositiveIntegerField",
  95    "PositiveSmallIntegerField",
  96    "SmallIntegerField",
  97    "TextField",
  98    "TimeField",
  99    "URLField",
 100    "UUIDField",
 101]
 102
 103
 104class Empty:
 105    pass
 106
 107
 108class NOT_PROVIDED:
 109    pass
 110
 111
 112# The values to use for "blank" in SelectFields. Will be appended to the start
 113# of most "choices" lists.
 114BLANK_CHOICE_DASH = [("", "---------")]
 115
 116
 117def _load_field(
 118    package_label: str, model_name: str, field_name: str
 119) -> Field[Any] | ForeignObjectRel:
 120    return models_registry.get_model(package_label, model_name)._model_meta.get_field(
 121        field_name
 122    )
 123
 124
 125# A guide to Field parameters:
 126#
 127#   * name:      The name of the field specified in the model.
 128#   * attname:   The attribute to use on the model object. This is the same as
 129#                "name", except in the case of ForeignKeys, where "_id" is
 130#                appended.
 131#   * column:    The database column for this field. This is the same as
 132#                "attname".
 133#
 134# Code that introspects values, or does other dynamic things, should use
 135# attname.
 136
 137
 138def _empty(of_cls: type) -> Empty:
 139    new = Empty()
 140    new.__class__ = of_cls
 141    return new
 142
 143
 144def return_None() -> None:
 145    return None
 146
 147
 148# TypeVar for Field's generic type parameter
 149T = TypeVar("T")
 150
 151
 152class Field(RegisterLookupMixin, Generic[T]):
 153    """Base class for all field types"""
 154
 155    # Instance attributes set during field lifecycle
 156    # Set by __init__
 157    name: str | None
 158    max_length: int | None
 159    # Set by set_attributes_from_name (called by contribute_to_class)
 160    attname: str
 161    column: str
 162    concrete: bool
 163    # Set by contribute_to_class
 164    model: type[Model]
 165
 166    # Designates whether empty strings fundamentally are allowed at the
 167    # database level.
 168    empty_strings_allowed = True
 169    empty_values = list(validators.EMPTY_VALUES)
 170
 171    default_validators = []  # Default set of validators
 172    default_error_messages = {
 173        "invalid_choice": "Value %(value)r is not a valid choice.",
 174        "allow_null": "This field cannot be null.",
 175        "required": "This field is be required.",
 176        "unique": "A %(model_name)s with this %(field_label)s already exists.",
 177    }
 178
 179    # Attributes that don't affect a column definition.
 180    # These attributes are ignored when altering the field.
 181    non_db_attrs = (
 182        "required",
 183        "choices",
 184        "error_messages",
 185        "limit_choices_to",
 186        # Database-level options are not supported, see #21961.
 187        "on_delete",
 188        "related_query_name",
 189        "validators",
 190    )
 191
 192    # Generic field type description, usually overridden by subclasses
 193    def _description(self) -> str:
 194        return f"Field of type: {self.__class__.__name__}"
 195
 196    description = property(_description)
 197
 198    def __init__(
 199        self,
 200        *,
 201        max_length: int | None = None,
 202        required: bool = True,
 203        allow_null: bool = False,
 204        default: Any = NOT_PROVIDED,
 205        choices: Any = None,
 206        validators: Sequence[Callable[..., Any]] = (),
 207        error_messages: dict[str, str] | None = None,
 208    ):
 209        self.name = None  # Set by set_attributes_from_name
 210        self.max_length = max_length
 211        self.required, self.allow_null = required, allow_null
 212        self.default = default
 213        if isinstance(choices, ChoicesMeta):
 214            choices = choices.choices
 215        elif isinstance(choices, enum.EnumMeta):
 216            choices = [(member.value, member.name) for member in choices]
 217        if isinstance(choices, collections.abc.Iterator):
 218            choices = list(choices)
 219        self.choices = choices
 220
 221        self.primary_key = False
 222        self.auto_created = False
 223
 224        self._validators = list(validators)  # Store for deconstruction later
 225
 226        self._error_messages = error_messages  # Store for deconstruction later
 227
 228    def __str__(self) -> str:
 229        """
 230        Return "package_label.model_label.field_name" for fields attached to
 231        models.
 232        """
 233        if not hasattr(self, "model"):
 234            return super().__str__()
 235        model = self.model
 236        return f"{model.model_options.label}.{self.name}"
 237
 238    def __repr__(self) -> str:
 239        """Display the module, class, and name of the field."""
 240        path = f"{self.__class__.__module__}.{self.__class__.__qualname__}"
 241        name = getattr(self, "name", None)
 242        if name is not None:
 243            return f"<{path}: {name}>"
 244        return f"<{path}>"
 245
 246    def preflight(self, **kwargs: Any) -> list[PreflightResult]:
 247        return [
 248            *self._check_field_name(),
 249            *self._check_choices(),
 250            *self._check_null_allowed_for_primary_keys(),
 251            *self._check_validators(),
 252        ]
 253
 254    def _check_field_name(self) -> list[PreflightResult]:
 255        """
 256        Check if field name is valid, i.e. 1) does not end with an
 257        underscore, 2) does not contain "__" and 3) is not "id".
 258        """
 259        assert self.name is not None, "Field name must be set before checking"
 260        if self.name.endswith("_"):
 261            return [
 262                PreflightResult(
 263                    fix="Field names must not end with an underscore.",
 264                    obj=self,
 265                    id="fields.name_ends_with_underscore",
 266                )
 267            ]
 268        elif LOOKUP_SEP in self.name:
 269            return [
 270                PreflightResult(
 271                    fix=f'Field names must not contain "{LOOKUP_SEP}".',
 272                    obj=self,
 273                    id="fields.name_contains_lookup_separator",
 274                )
 275            ]
 276        elif self.name == "id":
 277            return [
 278                PreflightResult(
 279                    fix="'id' is a reserved word that cannot be used as a field name.",
 280                    obj=self,
 281                    id="fields.reserved_field_name_id",
 282                )
 283            ]
 284        else:
 285            return []
 286
 287    @classmethod
 288    def _choices_is_value(cls, value: Any) -> bool:
 289        return isinstance(value, str | Promise) or not is_iterable(value)
 290
 291    def _check_choices(self) -> list[PreflightResult]:
 292        if not self.choices:
 293            return []
 294
 295        if not is_iterable(self.choices) or isinstance(self.choices, str):
 296            return [
 297                PreflightResult(
 298                    fix="'choices' must be an iterable (e.g., a list or tuple).",
 299                    obj=self,
 300                    id="fields.choices_not_iterable",
 301                )
 302            ]
 303
 304        choice_max_length = 0
 305        # Expect [group_name, [value, display]]
 306        for choices_group in self.choices:
 307            try:
 308                group_name, group_choices = choices_group
 309            except (TypeError, ValueError):
 310                # Containing non-pairs
 311                break
 312            try:
 313                if not all(
 314                    self._choices_is_value(value) and self._choices_is_value(human_name)
 315                    for value, human_name in group_choices
 316                ):
 317                    break
 318                if self.max_length is not None and group_choices:
 319                    choice_max_length = max(
 320                        [
 321                            choice_max_length,
 322                            *(
 323                                len(value)
 324                                for value, _ in group_choices
 325                                if isinstance(value, str)
 326                            ),
 327                        ]
 328                    )
 329            except (TypeError, ValueError):
 330                # No groups, choices in the form [value, display]
 331                value, human_name = group_name, group_choices
 332                if not self._choices_is_value(value) or not self._choices_is_value(
 333                    human_name
 334                ):
 335                    break
 336                if self.max_length is not None and isinstance(value, str):
 337                    choice_max_length = max(choice_max_length, len(value))
 338
 339            # Special case: choices=['ab']
 340            if isinstance(choices_group, str):
 341                break
 342        else:
 343            if self.max_length is not None and choice_max_length > self.max_length:
 344                return [
 345                    PreflightResult(
 346                        fix="'max_length' is too small to fit the longest value "  # noqa: UP031
 347                        "in 'choices' (%d characters)." % choice_max_length,
 348                        obj=self,
 349                        id="fields.max_length_too_small_for_choices",
 350                    ),
 351                ]
 352            return []
 353
 354        return [
 355            PreflightResult(
 356                fix="'choices' must be an iterable containing "
 357                "(actual value, human readable name) tuples.",
 358                obj=self,
 359                id="fields.choices_invalid_format",
 360            )
 361        ]
 362
 363    def _check_null_allowed_for_primary_keys(self) -> list[PreflightResult]:
 364        if self.primary_key and self.allow_null:
 365            return [
 366                PreflightResult(
 367                    fix="Primary keys must not have allow_null=True. "
 368                    "Set allow_null=False on the field, or "
 369                    "remove primary_key=True argument.",
 370                    obj=self,
 371                    id="fields.primary_key_allows_null",
 372                )
 373            ]
 374        else:
 375            return []
 376
 377    def _check_validators(self) -> list[PreflightResult]:
 378        errors = []
 379        for i, validator in enumerate(self.validators):
 380            if not callable(validator):
 381                errors.append(
 382                    PreflightResult(
 383                        fix=(
 384                            "All 'validators' must be callable. "
 385                            f"validators[{i}] ({repr(validator)}) isn't a function or "
 386                            "instance of a validator class."
 387                        ),
 388                        obj=self,
 389                        id="fields.invalid_validator",
 390                    )
 391                )
 392        return errors
 393
 394    def get_col(self, alias: str | None, output_field: Field | None = None) -> Col:
 395        if alias == self.model.model_options.db_table and (
 396            output_field is None or output_field == self
 397        ):
 398            return self.cached_col
 399        from plain.models.expressions import Col
 400
 401        return Col(alias, self, output_field)
 402
 403    @cached_property
 404    def cached_col(self) -> Col:
 405        from plain.models.expressions import Col
 406
 407        return Col(self.model.model_options.db_table, self)
 408
 409    def select_format(
 410        self, compiler: SQLCompiler, sql: str, params: Any
 411    ) -> tuple[str, Any]:
 412        """
 413        Custom format for select clauses.
 414        """
 415        return sql, params
 416
 417    def deconstruct(self) -> tuple[str | None, str, list[Any], dict[str, Any]]:
 418        """
 419        Return enough information to recreate the field as a 4-tuple:
 420
 421         * The name of the field on the model, if contribute_to_class() has
 422           been run.
 423         * The import path of the field, including the class, e.g.
 424           plain.models.IntegerField. This should be the most portable
 425           version, so less specific may be better.
 426         * A list of positional arguments.
 427         * A dict of keyword arguments.
 428
 429        Note that the positional or keyword arguments must contain values of
 430        the following types (including inner values of collection types):
 431
 432         * None, bool, str, int, float, complex, set, frozenset, list, tuple,
 433           dict
 434         * UUID
 435         * datetime.datetime (naive), datetime.date
 436         * top-level classes, top-level functions - will be referenced by their
 437           full import path
 438         * Storage instances - these have their own deconstruct() method
 439
 440        This is because the values here must be serialized into a text format
 441        (possibly new Python code, possibly JSON) and these are the only types
 442        with encoding handlers defined.
 443
 444        There's no need to return the exact way the field was instantiated this
 445        time, just ensure that the resulting field is the same - prefer keyword
 446        arguments over positional ones, and omit parameters with their default
 447        values.
 448        """
 449        # Short-form way of fetching all the default parameters
 450        keywords = {}
 451        possibles = {
 452            "max_length": None,
 453            "required": True,
 454            "allow_null": False,
 455            "default": NOT_PROVIDED,
 456            "choices": None,
 457            "validators": [],
 458            "error_messages": None,
 459        }
 460        attr_overrides = {
 461            "error_messages": "_error_messages",
 462            "validators": "_validators",
 463        }
 464        equals_comparison = {"choices", "validators"}
 465        for name, default in possibles.items():
 466            value = getattr(self, attr_overrides.get(name, name))
 467            # Unroll anything iterable for choices into a concrete list
 468            if name == "choices" and isinstance(value, collections.abc.Iterable):
 469                value = list(value)
 470            # Do correct kind of comparison
 471            if name in equals_comparison:
 472                if value != default:
 473                    keywords[name] = value
 474            else:
 475                if value is not default:
 476                    keywords[name] = value
 477        # Work out path - we shorten it for known Plain core fields
 478        path = f"{self.__class__.__module__}.{self.__class__.__qualname__}"
 479        if path.startswith("plain.models.fields.related"):
 480            path = path.replace("plain.models.fields.related", "plain.models")
 481        elif path.startswith("plain.models.fields.json"):
 482            path = path.replace("plain.models.fields.json", "plain.models")
 483        elif path.startswith("plain.models.fields.proxy"):
 484            path = path.replace("plain.models.fields.proxy", "plain.models")
 485        elif path.startswith("plain.models.fields.timezones"):
 486            path = path.replace("plain.models.fields.timezones", "plain.models")
 487        elif path.startswith("plain.models.fields"):
 488            path = path.replace("plain.models.fields", "plain.models")
 489        # Return basic info - other fields should override this.
 490        # Note: self.name can be None during migration state rendering when fields are cloned
 491        return (self.name, path, [], keywords)
 492
 493    def clone(self) -> Self:
 494        """
 495        Uses deconstruct() to clone a new copy of this Field.
 496        Will not preserve any class attachments/attribute names.
 497        """
 498        name, path, args, kwargs = self.deconstruct()
 499        return self.__class__(*args, **kwargs)
 500
 501    def __deepcopy__(self, memodict: dict[int, Any]) -> Self:
 502        # We don't have to deepcopy very much here, since most things are not
 503        # intended to be altered after initial creation.
 504        obj = copy.copy(self)
 505        memodict[id(self)] = obj
 506        return obj
 507
 508    def __copy__(self) -> Self:
 509        # We need to avoid hitting __reduce__, so define this
 510        # slightly weird copy construct.
 511        obj = Empty()
 512        obj.__class__ = self.__class__
 513        obj.__dict__ = self.__dict__.copy()
 514        return cast(Self, obj)
 515
 516    def __reduce__(
 517        self,
 518    ) -> (
 519        tuple[Callable[..., Any], tuple[Any, ...], dict[str, Any]]
 520        | tuple[Callable[..., Field[Any] | ForeignObjectRel], tuple[str, str, str]]
 521    ):
 522        """
 523        Pickling should return the model._model_meta.fields instance of the field,
 524        not a new copy of that field. So, use the app registry to load the
 525        model and then the field back.
 526        """
 527        model = getattr(self, "model", None)
 528        if model is None:
 529            # Fields are sometimes used without attaching them to models (for
 530            # example in aggregation). In this case give back a plain field
 531            # instance. The code below will create a new empty instance of
 532            # class self.__class__, then update its dict with self.__dict__
 533            # values - so, this is very close to normal pickle.
 534            state = self.__dict__.copy()
 535            # The _get_default cached_property can't be pickled due to lambda
 536            # usage.
 537            state.pop("_get_default", None)
 538            return _empty, (self.__class__,), state
 539        assert self.name is not None
 540        options = model.model_options
 541        return _load_field, (
 542            options.package_label,
 543            options.object_name,
 544            self.name,
 545        )
 546
 547    def get_id_value_on_save(self, instance: Model) -> T | None:
 548        """
 549        Hook to generate new primary key values on save. This method is called when
 550        saving instances with no primary key value set. If this method returns
 551        something else than None, then the returned value is used when saving
 552        the new instance.
 553        """
 554        if self.default:
 555            return self.get_default()
 556        return None
 557
 558    def to_python(self, value: Any) -> T | None:
 559        """
 560        Convert the input value into the expected Python data type, raising
 561        plain.exceptions.ValidationError if the data can't be converted.
 562        Return the converted value. Subclasses should override this.
 563        """
 564        return value
 565
 566    @cached_property
 567    def error_messages(self) -> dict[str, str]:
 568        messages = {}
 569        for c in reversed(self.__class__.__mro__):
 570            messages.update(getattr(c, "default_error_messages", {}))
 571        messages.update(self._error_messages or {})
 572        return messages
 573
 574    @cached_property
 575    def validators(self) -> list[Callable[..., Any]]:
 576        """
 577        Some validators can't be created at field initialization time.
 578        This method provides a way to delay their creation until required.
 579        """
 580        return [*self.default_validators, *self._validators]
 581
 582    def run_validators(self, value: Any) -> None:
 583        if value in self.empty_values:
 584            return
 585
 586        errors = []
 587        for v in self.validators:
 588            try:
 589                v(value)
 590            except exceptions.ValidationError as e:
 591                if hasattr(e, "code") and e.code in self.error_messages:
 592                    e.message = self.error_messages[e.code]
 593                errors.extend(e.error_list)
 594
 595        if errors:
 596            raise exceptions.ValidationError(errors)
 597
 598    def validate(self, value: Any, model_instance: Model) -> None:
 599        """
 600        Validate value and raise ValidationError if necessary. Subclasses
 601        should override this to provide validation logic.
 602        """
 603
 604        if self.choices is not None and value not in self.empty_values:
 605            for option_key, option_value in self.choices:
 606                if isinstance(option_value, list | tuple):
 607                    # This is an optgroup, so look inside the group for
 608                    # options.
 609                    for optgroup_key, optgroup_value in option_value:
 610                        if value == optgroup_key:
 611                            return
 612                elif value == option_key:
 613                    return
 614            raise exceptions.ValidationError(
 615                self.error_messages["invalid_choice"],
 616                code="invalid_choice",
 617                params={"value": value},
 618            )
 619
 620        if value is None and not self.allow_null:
 621            raise exceptions.ValidationError(
 622                self.error_messages["allow_null"], code="allow_null"
 623            )
 624
 625        if self.required and value in self.empty_values:
 626            raise exceptions.ValidationError(
 627                self.error_messages["required"], code="required"
 628            )
 629
 630    def clean(self, value: Any, model_instance: Model) -> T | None:
 631        """
 632        Convert the value's type and run validation. Validation errors
 633        from to_python() and validate() are propagated. Return the correct
 634        value if no error is raised.
 635        """
 636        value = self.to_python(value)
 637        self.validate(value, model_instance)
 638        self.run_validators(value)
 639        return value
 640
 641    def db_type_parameters(self) -> DictWrapper:
 642        return DictWrapper(self.__dict__, quote_name, "qn_")
 643
 644    def db_check(self) -> str | None:
 645        """
 646        Return the database column check constraint for this field.
 647        Works the same way as db_type() for the case that
 648        get_internal_type() does not map to a preexisting model field.
 649        """
 650        data = self.db_type_parameters()
 651        try:
 652            return DATA_TYPE_CHECK_CONSTRAINTS[self.get_internal_type()] % data
 653        except KeyError:
 654            return None
 655
 656    def db_type(self) -> str | None:
 657        """
 658        Return the database column data type for this field.
 659        """
 660        # The default implementation of this method looks at the
 661        # backend-specific data_types dictionary, looking up the field by its
 662        # "internal type".
 663        #
 664        # A Field class can implement the get_internal_type() method to specify
 665        # which *preexisting* Plain Field class it's most similar to -- i.e.,
 666        # a custom field might be represented by a TEXT column type, which is
 667        # the same as the TextField Plain field type, which means the custom
 668        # field's get_internal_type() returns 'TextField'.
 669        #
 670        # But the limitation of the get_internal_type() / data_types approach
 671        # is that it cannot handle database column types that aren't already
 672        # mapped to one of the built-in Plain field types. In this case, you
 673        # can implement db_type() instead of get_internal_type() to specify
 674        # exactly which wacky database column type you want to use.
 675        data = self.db_type_parameters()
 676        try:
 677            column_type = DATA_TYPES[self.get_internal_type()]
 678        except KeyError:
 679            return None
 680        else:
 681            # column_type is either a single-parameter function or a string.
 682            if callable(column_type):
 683                return column_type(data)
 684            return column_type % data
 685
 686    def rel_db_type(self) -> str | None:
 687        """
 688        Return the data type that a related field pointing to this field should
 689        use. For example, this method is called by ForeignKeyField to determine its data type.
 690        """
 691        return self.db_type()
 692
 693    def cast_db_type(self) -> str | None:
 694        """Return the data type to use in the Cast() function."""
 695        db_type = CAST_DATA_TYPES.get(self.get_internal_type())
 696        if db_type:
 697            return db_type % self.db_type_parameters()
 698        return self.db_type()
 699
 700    def db_parameters(self) -> DbParameters:
 701        """
 702        Extension of db_type(), providing a range of different return values
 703        (type, checks). This will look at db_type(), allowing custom model
 704        fields to override it.
 705        """
 706        type_string = self.db_type()
 707        check_string = self.db_check()
 708        return {
 709            "type": type_string,
 710            "check": check_string,
 711        }
 712
 713    def db_type_suffix(self) -> str | None:
 714        return DATA_TYPES_SUFFIX.get(self.get_internal_type())
 715
 716    def get_db_converters(
 717        self, connection: DatabaseWrapper
 718    ) -> list[Callable[..., Any]]:
 719        if from_db_value := getattr(self, "from_db_value", None):
 720            return [from_db_value]
 721        return []
 722
 723    @property
 724    def db_returning(self) -> bool:
 725        """
 726        Private API intended only to be used by Plain itself. Currently only
 727        the PostgreSQL backend supports returning multiple fields on a model.
 728        """
 729        return False
 730
 731    def set_attributes_from_name(self, name: str) -> None:
 732        self.name = self.name or name
 733        self.attname = self.get_attname()
 734        self.column = self.attname
 735        self.concrete = self.column is not None
 736
 737    def contribute_to_class(self, cls: type[Model], name: str) -> None:
 738        """
 739        Register the field with the model class it belongs to.
 740
 741        Field now acts as its own descriptor - it stays on the class and handles
 742        __get__/__set__/__delete__ directly.
 743        """
 744        self.set_attributes_from_name(name)
 745        self.model = cls
 746        cls._model_meta.add_field(self)
 747
 748        # Field is now a descriptor itself - ensure it's set on the class
 749        # This is important for inherited fields that get deepcopied in Meta.__get__
 750        if self.column:
 751            setattr(cls, self.attname, self)
 752
 753    # Descriptor protocol implementation
 754    @overload
 755    def __get__(self, instance: None, owner: type[Model]) -> Self: ...
 756
 757    @overload
 758    def __get__(self, instance: Model, owner: type[Model]) -> T: ...
 759
 760    def __get__(self, instance: Model | None, owner: type[Model]) -> Self | T:
 761        """
 762        Descriptor __get__ for attribute access.
 763
 764        Class access (User.email) returns the Field descriptor itself.
 765        Instance access (user.email) returns the field value from instance.__dict__,
 766        with lazy loading support if the value is not yet loaded.
 767        """
 768        # Class access - return the Field descriptor
 769        if instance is None:
 770            return self
 771
 772        # If field hasn't been contributed to a class yet (e.g., used standalone
 773        # as an output_field in aggregates), just return self
 774        if not hasattr(self, "attname"):
 775            return self
 776
 777        # Instance access - get value from instance dict
 778        data = instance.__dict__
 779        field_name = self.attname
 780
 781        # If value not in dict, lazy load from database
 782        if field_name not in data:
 783            # Deferred field - load it from the database
 784            instance.refresh_from_db(fields=[field_name])
 785
 786        return cast(T, data.get(field_name))
 787
 788    def __set__(self, instance: Model, value: Any) -> None:
 789        """
 790        Descriptor __set__ for attribute assignment.
 791
 792        Validates and converts the value using to_python(), then stores it
 793        in instance.__dict__[attname].
 794        """
 795        # Safety check: ensure field has been properly initialized
 796        if not hasattr(self, "attname"):
 797            raise AttributeError(
 798                f"Field {self.__class__.__name__} has not been initialized properly. "
 799                f"The field's contribute_to_class() has not been called yet. "
 800                f"This usually means the field is being used before it was added to a model class."
 801            )
 802
 803        # Convert/validate the value
 804        if value is not None:
 805            value = self.to_python(value)
 806
 807        # Store in instance dict
 808        instance.__dict__[self.attname] = value
 809
 810    def __delete__(self, instance: Model) -> None:
 811        """
 812        Descriptor __delete__ for attribute deletion.
 813
 814        Removes the value from instance.__dict__.
 815        """
 816        try:
 817            del instance.__dict__[self.attname]
 818        except KeyError:
 819            raise AttributeError(
 820                f"{instance.__class__.__name__!r} object has no attribute {self.attname!r}"
 821            )
 822
 823    def get_attname(self) -> str:
 824        assert self.name is not None  # Field name must be set
 825        return self.name
 826
 827    def get_internal_type(self) -> str:
 828        return self.__class__.__name__
 829
 830    def pre_save(self, model_instance: Model, add: bool) -> T | None:
 831        """Return field's value just before saving."""
 832        return getattr(model_instance, self.attname)
 833
 834    def get_prep_value(self, value: Any) -> Any:
 835        """Perform preliminary non-db specific value checks and conversions."""
 836        if isinstance(value, Promise):
 837            value = value._proxy____cast()
 838        return value
 839
 840    def get_db_prep_value(
 841        self, value: Any, connection: DatabaseWrapper, prepared: bool = False
 842    ) -> Any:
 843        """
 844        Return field's value prepared for interacting with the database backend.
 845
 846        Used by the default implementations of get_db_prep_save().
 847        """
 848        if not prepared:
 849            value = self.get_prep_value(value)
 850        return value
 851
 852    def get_db_prep_save(self, value: Any, connection: DatabaseWrapper) -> Any:
 853        """Return field's value prepared for saving into a database."""
 854        if hasattr(value, "as_sql"):
 855            return value
 856        return self.get_db_prep_value(value, connection=connection, prepared=False)
 857
 858    def has_default(self) -> bool:
 859        """Return a boolean of whether this field has a default value."""
 860        return self.default is not NOT_PROVIDED
 861
 862    def get_default(self) -> T | None:
 863        """Return the default value for this field."""
 864        return self._get_default()
 865
 866    @cached_property
 867    def _get_default(self) -> Callable[[], Any]:
 868        if self.has_default():
 869            if callable(self.default):
 870                return self.default
 871            return lambda: self.default
 872
 873        if not self.empty_strings_allowed or self.allow_null:
 874            return return_None
 875        return str  # return empty string
 876
 877    def get_limit_choices_to(self) -> Any:
 878        """
 879        Return ``limit_choices_to`` for this model field.
 880        Overridden by related fields (ForeignKey, etc.).
 881        """
 882        raise NotImplementedError(
 883            "get_limit_choices_to() should only be called on related fields"
 884        )
 885
 886    def get_choices(
 887        self,
 888        include_blank: bool = True,
 889        blank_choice: list[tuple[str, str]] = BLANK_CHOICE_DASH,
 890        limit_choices_to: Any = None,
 891        ordering: tuple[str, ...] = (),
 892    ) -> list[tuple[Any, str]]:
 893        """
 894        Return choices with a default blank choices included, for use
 895        as <select> choices for this field.
 896        """
 897        if self.choices is not None:
 898            choices = list(self.choices)
 899            if include_blank:
 900                blank_defined = any(
 901                    choice in ("", None) for choice, _ in self.flatchoices
 902                )
 903                if not blank_defined:
 904                    choices = blank_choice + choices
 905            return choices
 906        remote_field = getattr(self, "remote_field", None)
 907        if remote_field is None or getattr(remote_field, "model", None) is None:
 908            return blank_choice if include_blank else []
 909        rel_model = remote_field.model
 910        limit_choices_to = limit_choices_to or self.get_limit_choices_to()
 911        related_field_name = (
 912            remote_field.get_related_field().attname
 913            if hasattr(remote_field, "get_related_field")
 914            else "id"
 915        )
 916        choice_func = operator.attrgetter(related_field_name)
 917        qs = rel_model.query.complex_filter(limit_choices_to)
 918        if ordering:
 919            qs = qs.order_by(*ordering)
 920        return (blank_choice if include_blank else []) + [
 921            (choice_func(x), str(x)) for x in qs
 922        ]
 923
 924    def value_to_string(self, obj: Model) -> str:
 925        """
 926        Return a string value of this field from the passed obj.
 927        This is used by the serialization framework.
 928        """
 929        return str(self.value_from_object(obj))
 930
 931    def _get_flatchoices(self) -> list[tuple[Any, Any]]:
 932        """Flattened version of choices tuple."""
 933        if self.choices is None:
 934            return []
 935        flat = []
 936        for choice, value in self.choices:
 937            if isinstance(value, list | tuple):
 938                flat.extend(value)
 939            else:
 940                flat.append((choice, value))
 941        return flat
 942
 943    flatchoices = property(_get_flatchoices)
 944
 945    def save_form_data(self, instance: Model, data: Any) -> None:
 946        assert self.name is not None
 947        setattr(instance, self.name, data)
 948
 949    def value_from_object(self, obj: Model) -> T | None:
 950        """Return the value of this field in the given model instance."""
 951        return getattr(obj, self.attname)
 952
 953
 954class BooleanField(Field[bool]):
 955    empty_strings_allowed = False
 956    default_error_messages = {
 957        "invalid": '"%(value)s" value must be either True or False.',
 958        "invalid_nullable": '"%(value)s" value must be either True, False, or None.',
 959    }
 960    description = "Boolean (Either True or False)"
 961
 962    def get_internal_type(self) -> str:
 963        return "BooleanField"
 964
 965    def to_python(self, value: Any) -> bool | None:
 966        if self.allow_null and value in self.empty_values:
 967            return None
 968        if value in (True, False):
 969            # 1/0 are equal to True/False. bool() converts former to latter.
 970            return bool(value)
 971        if value in ("t", "True", "1"):
 972            return True
 973        if value in ("f", "False", "0"):
 974            return False
 975        raise exceptions.ValidationError(
 976            self.error_messages["invalid_nullable" if self.allow_null else "invalid"],
 977            code="invalid",
 978            params={"value": value},
 979        )
 980
 981    def get_prep_value(self, value: Any) -> Any:
 982        value = super().get_prep_value(value)
 983        if value is None:
 984            return None
 985        return self.to_python(value)
 986
 987
 988class CharField(Field[str]):
 989    def __init__(self, **kwargs: Any):
 990        super().__init__(**kwargs)
 991        if self.max_length is not None:
 992            self.validators.append(validators.MaxLengthValidator(self.max_length))
 993
 994    @property
 995    def description(self) -> str:
 996        if self.max_length is not None:
 997            return "String (up to %(max_length)s)"
 998        else:
 999            return "String (unlimited)"
1000
1001    def preflight(self, **kwargs: Any) -> list[PreflightResult]:
1002        return [
1003            *super().preflight(**kwargs),
1004            *self._check_max_length_attribute(),
1005        ]
1006
1007    def _check_max_length_attribute(self, **kwargs: Any) -> list[PreflightResult]:
1008        # Unlimited VARCHAR is supported (no max_length required)
1009        if self.max_length is None:
1010            return []
1011        elif (
1012            not isinstance(self.max_length, int)
1013            or isinstance(self.max_length, bool)
1014            or self.max_length <= 0
1015        ):
1016            return [
1017                PreflightResult(
1018                    fix="'max_length' must be a positive integer.",
1019                    obj=self,
1020                    id="fields.charfield_invalid_max_length",
1021                )
1022            ]
1023        else:
1024            return []
1025
1026    def cast_db_type(self) -> str | None:
1027        if self.max_length is None:
1028            return CAST_CHAR_FIELD_WITHOUT_MAX_LENGTH
1029        return super().cast_db_type()
1030
1031    def get_internal_type(self) -> str:
1032        return "CharField"
1033
1034    def to_python(self, value: Any) -> str | None:
1035        if isinstance(value, str) or value is None:
1036            return value
1037        return str(value)
1038
1039    def get_prep_value(self, value: Any) -> Any:
1040        value = super().get_prep_value(value)
1041        return self.to_python(value)
1042
1043
1044def _to_naive(value: datetime.datetime) -> datetime.datetime:
1045    if timezone.is_aware(value):
1046        value = timezone.make_naive(value, datetime.UTC)
1047    return value
1048
1049
1050def _get_naive_now() -> datetime.datetime:
1051    return _to_naive(timezone.now())
1052
1053
1054class DateTimeCheckMixin(Field):
1055    auto_now: bool
1056    auto_now_add: bool
1057
1058    def preflight(self, **kwargs: Any) -> list[PreflightResult]:
1059        return [
1060            *super().preflight(**kwargs),
1061            *self._check_mutually_exclusive_options(),
1062            *self._check_fix_default_value(),
1063        ]
1064
1065    def _check_mutually_exclusive_options(self) -> list[PreflightResult]:
1066        # auto_now, auto_now_add, and default are mutually exclusive
1067        # options. The use of more than one of these options together
1068        # will trigger an Error
1069        mutually_exclusive_options = [
1070            self.auto_now_add,
1071            self.auto_now,
1072            self.has_default(),
1073        ]
1074        enabled_options = [
1075            option not in (None, False) for option in mutually_exclusive_options
1076        ].count(True)
1077        if enabled_options > 1:
1078            return [
1079                PreflightResult(
1080                    fix="The options auto_now, auto_now_add, and default "
1081                    "are mutually exclusive. Only one of these options "
1082                    "may be present.",
1083                    obj=self,
1084                    id="fields.datetime_auto_options_mutually_exclusive",
1085                )
1086            ]
1087        else:
1088            return []
1089
1090    def _check_fix_default_value(self) -> list[PreflightResult]:
1091        return []
1092
1093    # Concrete subclasses use this in their implementations of
1094    # _check_fix_default_value().
1095    def _check_if_value_fixed(
1096        self,
1097        value: datetime.date | datetime.datetime,
1098        now: datetime.datetime | None = None,
1099    ) -> list[PreflightResult]:
1100        """
1101        Check if the given value appears to have been provided as a "fixed"
1102        time value, and include a warning in the returned list if it does. The
1103        value argument must be a date object or aware/naive datetime object. If
1104        now is provided, it must be a naive datetime object.
1105        """
1106        if now is None:
1107            now = _get_naive_now()
1108        offset = datetime.timedelta(seconds=10)
1109        lower = now - offset
1110        upper = now + offset
1111        if isinstance(value, datetime.datetime):
1112            value = _to_naive(value)
1113        else:
1114            assert isinstance(value, datetime.date)
1115            lower = lower.date()
1116            upper = upper.date()
1117        if lower <= value <= upper:
1118            return [
1119                PreflightResult(
1120                    fix="Fixed default value provided. "
1121                    "It seems you set a fixed date / time / datetime "
1122                    "value as default for this field. This may not be "
1123                    "what you want. If you want to have the current date "
1124                    "as default, use `plain.utils.timezone.now`",
1125                    obj=self,
1126                    id="fields.datetime_naive_default_value",
1127                    warning=True,
1128                )
1129            ]
1130        return []
1131
1132
1133class DateField(DateTimeCheckMixin, Field[datetime.date]):
1134    empty_strings_allowed = False
1135    default_error_messages = {
1136        "invalid": '"%(value)s" value has an invalid date format. It must be in YYYY-MM-DD format.',
1137        "invalid_date": '"%(value)s" value has the correct format (YYYY-MM-DD) but it is an invalid date.',
1138    }
1139    description = "Date (without time)"
1140
1141    def __init__(
1142        self, *, auto_now: bool = False, auto_now_add: bool = False, **kwargs: Any
1143    ):
1144        self.auto_now, self.auto_now_add = auto_now, auto_now_add
1145        if auto_now or auto_now_add:
1146            kwargs["required"] = False
1147        super().__init__(**kwargs)
1148
1149    def _check_fix_default_value(self) -> list[PreflightResult]:
1150        """
1151        Warn that using an actual date or datetime value is probably wrong;
1152        it's only evaluated on server startup.
1153        """
1154        if not self.has_default():
1155            return []
1156
1157        value = self.default
1158        if isinstance(value, datetime.datetime):
1159            value = _to_naive(value).date()
1160        elif isinstance(value, datetime.date):
1161            pass
1162        else:
1163            # No explicit date / datetime value -- no checks necessary
1164            return []
1165        # At this point, value is a date object.
1166        return self._check_if_value_fixed(value)
1167
1168    def deconstruct(self) -> tuple[str | None, str, list[Any], dict[str, Any]]:
1169        name, path, args, kwargs = super().deconstruct()
1170        if self.auto_now:
1171            kwargs["auto_now"] = True
1172        if self.auto_now_add:
1173            kwargs["auto_now_add"] = True
1174        if self.auto_now or self.auto_now_add:
1175            del kwargs["required"]
1176        return name, path, args, kwargs
1177
1178    def get_internal_type(self) -> str:
1179        return "DateField"
1180
1181    def to_python(self, value: Any) -> datetime.date | None:
1182        if value is None:
1183            return value
1184        if isinstance(value, datetime.datetime):
1185            if timezone.is_aware(value):
1186                # Convert aware datetimes to the default time zone
1187                # before casting them to dates (#17742).
1188                default_timezone = timezone.get_default_timezone()
1189                value = timezone.make_naive(value, default_timezone)
1190            return value.date()
1191        if isinstance(value, datetime.date):
1192            return value
1193
1194        try:
1195            parsed = parse_date(value)
1196            if parsed is not None:
1197                return parsed
1198        except ValueError:
1199            raise exceptions.ValidationError(
1200                self.error_messages["invalid_date"],
1201                code="invalid_date",
1202                params={"value": value},
1203            )
1204
1205        raise exceptions.ValidationError(
1206            self.error_messages["invalid"],
1207            code="invalid",
1208            params={"value": value},
1209        )
1210
1211    def pre_save(self, model_instance: Model, add: bool) -> datetime.date | None:
1212        if self.auto_now or (self.auto_now_add and add):
1213            value = datetime.date.today()
1214            setattr(model_instance, self.attname, value)
1215            return value
1216        else:
1217            return super().pre_save(model_instance, add)
1218
1219    def get_prep_value(self, value: Any) -> Any:
1220        value = super().get_prep_value(value)
1221        return self.to_python(value)
1222
1223    def get_db_prep_value(
1224        self, value: Any, connection: DatabaseWrapper, prepared: bool = False
1225    ) -> Any:
1226        if not prepared:
1227            value = self.get_prep_value(value)
1228        return value
1229
1230    def value_to_string(self, obj: Model) -> str:
1231        val = self.value_from_object(obj)
1232        return "" if val is None else val.isoformat()
1233
1234
1235class DateTimeField(DateField):
1236    empty_strings_allowed = False
1237    default_error_messages = {
1238        "invalid": '"%(value)s" value has an invalid format. It must be in YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ] format.',
1239        "invalid_date": '"%(value)s" value has the correct format (YYYY-MM-DD) but it is an invalid date.',
1240        "invalid_datetime": '"%(value)s" value has the correct format (YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ]) but it is an invalid date/time.',
1241    }
1242    description = "Date (with time)"
1243
1244    # __init__ is inherited from DateField
1245
1246    def _check_fix_default_value(self) -> list[PreflightResult]:
1247        """
1248        Warn that using an actual date or datetime value is probably wrong;
1249        it's only evaluated on server startup.
1250        """
1251        if not self.has_default():
1252            return []
1253
1254        value = self.default
1255        if isinstance(value, datetime.datetime | datetime.date):
1256            return self._check_if_value_fixed(value)
1257        # No explicit date / datetime value -- no checks necessary.
1258        return []
1259
1260    def get_internal_type(self) -> str:
1261        return "DateTimeField"
1262
1263    def to_python(self, value: Any) -> datetime.datetime | None:
1264        if value is None:
1265            return value
1266        if isinstance(value, datetime.datetime):
1267            return value
1268        if isinstance(value, datetime.date):
1269            value = datetime.datetime(value.year, value.month, value.day)
1270
1271            # For backwards compatibility, interpret naive datetimes in
1272            # local time. This won't work during DST change, but we can't
1273            # do much about it, so we let the exceptions percolate up the
1274            # call stack.
1275            warnings.warn(
1276                f"DateTimeField {self.model.__name__}.{self.name} received a naive datetime "
1277                f"({value}) while time zone support is active.",
1278                RuntimeWarning,
1279            )
1280            default_timezone = timezone.get_default_timezone()
1281            value = timezone.make_aware(value, default_timezone)
1282
1283            return value
1284
1285        try:
1286            parsed = parse_datetime(value)
1287            if parsed is not None:
1288                return parsed
1289        except ValueError:
1290            raise exceptions.ValidationError(
1291                self.error_messages["invalid_datetime"],
1292                code="invalid_datetime",
1293                params={"value": value},
1294            )
1295
1296        try:
1297            parsed = parse_date(value)
1298            if parsed is not None:
1299                return datetime.datetime(parsed.year, parsed.month, parsed.day)
1300        except ValueError:
1301            raise exceptions.ValidationError(
1302                self.error_messages["invalid_date"],
1303                code="invalid_date",
1304                params={"value": value},
1305            )
1306
1307        raise exceptions.ValidationError(
1308            self.error_messages["invalid"],
1309            code="invalid",
1310            params={"value": value},
1311        )
1312
1313    def pre_save(self, model_instance: Model, add: bool) -> datetime.datetime | None:
1314        if self.auto_now or (self.auto_now_add and add):
1315            value = timezone.now()
1316            setattr(model_instance, self.attname, value)
1317            return value
1318        else:
1319            return getattr(model_instance, self.attname)
1320
1321    def get_prep_value(self, value: Any) -> Any:
1322        value = super().get_prep_value(value)
1323        value = self.to_python(value)
1324        if value is not None and timezone.is_naive(value):
1325            # For backwards compatibility, interpret naive datetimes in local
1326            # time. This won't work during DST change, but we can't do much
1327            # about it, so we let the exceptions percolate up the call stack.
1328            try:
1329                name = f"{self.model.__name__}.{self.name}"
1330            except AttributeError:
1331                name = "(unbound)"
1332            warnings.warn(
1333                f"DateTimeField {name} received a naive datetime ({value})"
1334                " while time zone support is active.",
1335                RuntimeWarning,
1336            )
1337            default_timezone = timezone.get_default_timezone()
1338            value = timezone.make_aware(value, default_timezone)
1339        return value
1340
1341    def get_db_prep_value(
1342        self, value: Any, connection: DatabaseWrapper, prepared: bool = False
1343    ) -> Any:
1344        if not prepared:
1345            value = self.get_prep_value(value)
1346        return value
1347
1348    def value_to_string(self, obj: Model) -> str:
1349        val = self.value_from_object(obj)
1350        return "" if val is None else val.isoformat()
1351
1352
1353class DecimalField(Field[decimal.Decimal]):
1354    empty_strings_allowed = False
1355    default_error_messages = {
1356        "invalid": '"%(value)s" value must be a decimal number.',
1357    }
1358    description = "Decimal number"
1359
1360    def __init__(
1361        self,
1362        *,
1363        max_digits: int | None = None,
1364        decimal_places: int | None = None,
1365        **kwargs: Any,
1366    ):
1367        self.max_digits, self.decimal_places = max_digits, decimal_places
1368        super().__init__(**kwargs)
1369
1370    def preflight(self, **kwargs: Any) -> list[PreflightResult]:
1371        errors = super().preflight(**kwargs)
1372
1373        digits_errors = [
1374            *self._check_decimal_places(),
1375            *self._check_max_digits(),
1376        ]
1377        if not digits_errors:
1378            errors.extend(self._check_decimal_places_and_max_digits())
1379        else:
1380            errors.extend(digits_errors)
1381        return errors
1382
1383    def _check_decimal_places(self) -> list[PreflightResult]:
1384        if self.decimal_places is None:
1385            return [
1386                PreflightResult(
1387                    fix="DecimalFields must define a 'decimal_places' attribute.",
1388                    obj=self,
1389                    id="fields.decimalfield_missing_decimal_places",
1390                )
1391            ]
1392        try:
1393            decimal_places = int(self.decimal_places)
1394            if decimal_places < 0:
1395                raise ValueError()
1396        except ValueError:
1397            return [
1398                PreflightResult(
1399                    fix="'decimal_places' must be a non-negative integer.",
1400                    obj=self,
1401                    id="fields.decimalfield_invalid_decimal_places",
1402                )
1403            ]
1404        else:
1405            return []
1406
1407    def _check_max_digits(self) -> list[PreflightResult]:
1408        if self.max_digits is None:
1409            return [
1410                PreflightResult(
1411                    fix="DecimalFields must define a 'max_digits' attribute.",
1412                    obj=self,
1413                    id="fields.decimalfield_missing_max_digits",
1414                )
1415            ]
1416        try:
1417            max_digits = int(self.max_digits)
1418            if max_digits <= 0:
1419                raise ValueError()
1420        except ValueError:
1421            return [
1422                PreflightResult(
1423                    fix="'max_digits' must be a positive integer.",
1424                    obj=self,
1425                    id="fields.decimalfield_invalid_max_digits",
1426                )
1427            ]
1428        else:
1429            return []
1430
1431    def _check_decimal_places_and_max_digits(self) -> list[PreflightResult]:
1432        if self.decimal_places is None or self.max_digits is None:
1433            return []
1434        if self.decimal_places > self.max_digits:
1435            return [
1436                PreflightResult(
1437                    fix="'max_digits' must be greater or equal to 'decimal_places'.",
1438                    obj=self,
1439                    id="fields.decimalfield_decimal_places_exceeds_max_digits",
1440                )
1441            ]
1442        return []
1443
1444    @cached_property
1445    def validators(self) -> list[Callable[..., Any]]:
1446        return super().validators + [
1447            validators.DecimalValidator(self.max_digits, self.decimal_places)
1448        ]
1449
1450    @cached_property
1451    def context(self) -> decimal.Context:
1452        return decimal.Context(prec=self.max_digits)
1453
1454    def deconstruct(self) -> tuple[str | None, str, list[Any], dict[str, Any]]:
1455        name, path, args, kwargs = super().deconstruct()
1456        if self.max_digits is not None:
1457            kwargs["max_digits"] = self.max_digits
1458        if self.decimal_places is not None:
1459            kwargs["decimal_places"] = self.decimal_places
1460        return name, path, args, kwargs
1461
1462    def get_internal_type(self) -> str:
1463        return "DecimalField"
1464
1465    def to_python(self, value: Any) -> decimal.Decimal | None:
1466        if value is None:
1467            return value
1468        try:
1469            if isinstance(value, float):
1470                decimal_value = self.context.create_decimal_from_float(value)
1471            else:
1472                decimal_value = decimal.Decimal(value)
1473        except (decimal.InvalidOperation, TypeError, ValueError):
1474            raise exceptions.ValidationError(
1475                self.error_messages["invalid"],
1476                code="invalid",
1477                params={"value": value},
1478            )
1479        if not decimal_value.is_finite():
1480            raise exceptions.ValidationError(
1481                self.error_messages["invalid"],
1482                code="invalid",
1483                params={"value": value},
1484            )
1485        return decimal_value
1486
1487    def get_db_prep_value(
1488        self, value: Any, connection: DatabaseWrapper, prepared: bool = False
1489    ) -> Any:
1490        if not prepared:
1491            value = self.get_prep_value(value)
1492        return value
1493
1494    def get_prep_value(self, value: Any) -> Any:
1495        value = super().get_prep_value(value)
1496        return self.to_python(value)
1497
1498
1499class DurationField(Field[datetime.timedelta]):
1500    """Store timedelta objects using PostgreSQL's interval type."""
1501
1502    empty_strings_allowed = False
1503    default_error_messages = {
1504        "invalid": '"%(value)s" value has an invalid format. It must be in [DD] [[HH:]MM:]ss[.uuuuuu] format.',
1505    }
1506    description = "Duration"
1507
1508    def get_internal_type(self) -> str:
1509        return "DurationField"
1510
1511    def to_python(self, value: Any) -> datetime.timedelta | None:
1512        if value is None:
1513            return value
1514        if isinstance(value, datetime.timedelta):
1515            return value
1516        try:
1517            parsed = parse_duration(value)
1518        except ValueError:
1519            pass
1520        else:
1521            if parsed is not None:
1522                return parsed
1523
1524        raise exceptions.ValidationError(
1525            self.error_messages["invalid"],
1526            code="invalid",
1527            params={"value": value},
1528        )
1529
1530    def get_db_prep_value(
1531        self, value: Any, connection: DatabaseWrapper, prepared: bool = False
1532    ) -> Any:
1533        # PostgreSQL has native interval (duration) type
1534        return value
1535
1536    def get_db_converters(
1537        self, connection: DatabaseWrapper
1538    ) -> list[Callable[..., Any]]:
1539        # PostgreSQL has native duration field, no converters needed
1540        return super().get_db_converters(connection)
1541
1542    def value_to_string(self, obj: Model) -> str:
1543        val = self.value_from_object(obj)
1544        return "" if val is None else duration_string(val)
1545
1546
1547class EmailField(CharField):
1548    default_validators = [validators.validate_email]
1549    description = "Email address"
1550
1551    def __init__(self, **kwargs: Any):
1552        # max_length=254 to be compliant with RFCs 3696 and 5321
1553        kwargs.setdefault("max_length", 254)
1554        super().__init__(**kwargs)
1555
1556    def deconstruct(self) -> tuple[str | None, str, list[Any], dict[str, Any]]:
1557        name, path, args, kwargs = super().deconstruct()
1558        # We do not exclude max_length if it matches default as we want to change
1559        # the default in future.
1560        return name, path, args, kwargs
1561
1562
1563class FloatField(Field[float]):
1564    empty_strings_allowed = False
1565    default_error_messages = {
1566        "invalid": '"%(value)s" value must be a float.',
1567    }
1568    description = "Floating point number"
1569
1570    def get_prep_value(self, value: Any) -> Any:
1571        value = super().get_prep_value(value)
1572        if value is None:
1573            return None
1574        try:
1575            return float(value)
1576        except (TypeError, ValueError) as e:
1577            raise e.__class__(
1578                f"Field '{self.name}' expected a number but got {value!r}.",
1579            ) from e
1580
1581    def get_internal_type(self) -> str:
1582        return "FloatField"
1583
1584    def to_python(self, value: Any) -> float | None:
1585        if value is None:
1586            return value
1587        try:
1588            return float(value)
1589        except (TypeError, ValueError):
1590            raise exceptions.ValidationError(
1591                self.error_messages["invalid"],
1592                code="invalid",
1593                params={"value": value},
1594            )
1595
1596
1597class IntegerField(Field[int]):
1598    empty_strings_allowed = False
1599    default_error_messages = {
1600        "invalid": '"%(value)s" value must be an integer.',
1601    }
1602    description = "Integer"
1603
1604    def preflight(self, **kwargs: Any) -> list[PreflightResult]:
1605        return [
1606            *super().preflight(**kwargs),
1607            *self._check_max_length_warning(),
1608        ]
1609
1610    def _check_max_length_warning(self) -> list[PreflightResult]:
1611        if self.max_length is not None:
1612            return [
1613                PreflightResult(
1614                    fix=f"'max_length' is ignored when used with {self.__class__.__name__}. Remove 'max_length' from field.",
1615                    obj=self,
1616                    id="fields.max_length_ignored",
1617                    warning=True,
1618                )
1619            ]
1620        return []
1621
1622    @cached_property
1623    def validators(self) -> list[Callable[..., Any]]:
1624        # These validators can't be added at field initialization time since
1625        # they're based on values retrieved from the database connection.
1626        validators_ = super().validators
1627        internal_type = self.get_internal_type()
1628        min_value, max_value = INTEGER_FIELD_RANGES[internal_type]
1629        if min_value is not None and not any(
1630            (
1631                isinstance(validator, validators.MinValueValidator)
1632                and (
1633                    validator.limit_value()
1634                    if callable(validator.limit_value)
1635                    else validator.limit_value
1636                )
1637                >= min_value
1638            )
1639            for validator in validators_
1640        ):
1641            validators_.append(validators.MinValueValidator(min_value))
1642        if max_value is not None and not any(
1643            (
1644                isinstance(validator, validators.MaxValueValidator)
1645                and (
1646                    validator.limit_value()
1647                    if callable(validator.limit_value)
1648                    else validator.limit_value
1649                )
1650                <= max_value
1651            )
1652            for validator in validators_
1653        ):
1654            validators_.append(validators.MaxValueValidator(max_value))
1655        return validators_
1656
1657    def get_prep_value(self, value: Any) -> Any:
1658        value = super().get_prep_value(value)
1659        if value is None:
1660            return None
1661        try:
1662            return int(value)
1663        except (TypeError, ValueError) as e:
1664            raise e.__class__(
1665                f"Field '{self.name}' expected a number but got {value!r}.",
1666            ) from e
1667
1668    def get_db_prep_value(
1669        self, value: Any, connection: DatabaseWrapper, prepared: bool = False
1670    ) -> Any:
1671        value = super().get_db_prep_value(value, connection, prepared)
1672        return adapt_integerfield_value(value, self.get_internal_type())
1673
1674    def get_internal_type(self) -> str:
1675        return "IntegerField"
1676
1677    def to_python(self, value: Any) -> int | None:
1678        if value is None:
1679            return value
1680        try:
1681            return int(value)
1682        except (TypeError, ValueError):
1683            raise exceptions.ValidationError(
1684                self.error_messages["invalid"],
1685                code="invalid",
1686                params={"value": value},
1687            )
1688
1689
1690class BigIntegerField(IntegerField):
1691    description = "Big (8 byte) integer"
1692
1693    def get_internal_type(self) -> str:
1694        return "BigIntegerField"
1695
1696
1697class SmallIntegerField(IntegerField):
1698    description = "Small integer"
1699
1700    def get_internal_type(self) -> str:
1701        return "SmallIntegerField"
1702
1703
1704class GenericIPAddressField(Field[str]):
1705    empty_strings_allowed = False
1706    description = "IP address"
1707    default_error_messages = {}
1708
1709    def __init__(
1710        self,
1711        *,
1712        protocol: str = "both",
1713        unpack_ipv4: bool = False,
1714        **kwargs: Any,
1715    ):
1716        self.unpack_ipv4 = unpack_ipv4
1717        self.protocol = protocol
1718        (
1719            self.default_validators,
1720            invalid_error_message,
1721        ) = validators.ip_address_validators(protocol, unpack_ipv4)
1722        self.default_error_messages["invalid"] = invalid_error_message
1723        kwargs["max_length"] = 39
1724        super().__init__(**kwargs)
1725
1726    def preflight(self, **kwargs: Any) -> list[PreflightResult]:
1727        return [
1728            *super().preflight(**kwargs),
1729            *self._check_required_and_null_values(),
1730        ]
1731
1732    def _check_required_and_null_values(self) -> list[PreflightResult]:
1733        if not getattr(self, "allow_null", False) and not getattr(
1734            self, "required", True
1735        ):
1736            return [
1737                PreflightResult(
1738                    fix="GenericIPAddressFields cannot have required=False if allow_null=False, "
1739                    "as blank values are stored as nulls.",
1740                    obj=self,
1741                    id="fields.generic_ip_field_null_blank_config",
1742                )
1743            ]
1744        return []
1745
1746    def deconstruct(self) -> tuple[str | None, str, list[Any], dict[str, Any]]:
1747        name, path, args, kwargs = super().deconstruct()
1748        if self.unpack_ipv4 is not False:
1749            kwargs["unpack_ipv4"] = self.unpack_ipv4
1750        if self.protocol != "both":
1751            kwargs["protocol"] = self.protocol
1752        if kwargs.get("max_length") == 39:
1753            del kwargs["max_length"]
1754        return name, path, args, kwargs
1755
1756    def get_internal_type(self) -> str:
1757        return "GenericIPAddressField"
1758
1759    def to_python(self, value: Any) -> str | None:
1760        if value is None:
1761            return None
1762        if not isinstance(value, str):
1763            value = str(value)
1764        value = value.strip()
1765        if ":" in value:
1766            return clean_ipv6_address(
1767                value, self.unpack_ipv4, self.error_messages["invalid"]
1768            )
1769        return value
1770
1771    def get_db_prep_value(
1772        self, value: Any, connection: DatabaseWrapper, prepared: bool = False
1773    ) -> Any:
1774        if not prepared:
1775            value = self.get_prep_value(value)
1776        return adapt_ipaddressfield_value(value)
1777
1778    def get_prep_value(self, value: Any) -> Any:
1779        value = super().get_prep_value(value)
1780        if value is None:
1781            return None
1782        if value and ":" in value:
1783            try:
1784                return clean_ipv6_address(value, self.unpack_ipv4)
1785            except exceptions.ValidationError:
1786                pass
1787        return str(value)
1788
1789
1790class _HasDbType(Protocol):
1791    """Protocol for objects that have a db_type method and integer_field_class."""
1792
1793    integer_field_class: type[IntegerField]
1794
1795    def db_type(self) -> str | None: ...
1796
1797
1798class PositiveIntegerRelDbTypeMixin(IntegerField):
1799    integer_field_class: type[IntegerField]
1800
1801    def __init_subclass__(cls, **kwargs: Any) -> None:
1802        super().__init_subclass__(**kwargs)
1803        if not hasattr(cls, "integer_field_class"):
1804            # Find the first IntegerField parent in the MRO
1805            integer_parent = next(
1806                (
1807                    parent
1808                    for parent in cls.__mro__[1:]
1809                    if issubclass(parent, IntegerField)
1810                ),
1811                None,
1812            )
1813            if integer_parent is not None:
1814                cls.integer_field_class = integer_parent
1815
1816    def rel_db_type(self: _HasDbType) -> str | None:
1817        """
1818        Return the data type that a related field pointing to this field should
1819        use. PostgreSQL uses standard integer types for foreign keys.
1820        """
1821        return self.integer_field_class().db_type()
1822
1823
1824class PositiveBigIntegerField(PositiveIntegerRelDbTypeMixin, BigIntegerField):
1825    description = "Positive big integer"
1826
1827    def get_internal_type(self) -> str:
1828        return "PositiveBigIntegerField"
1829
1830
1831class PositiveIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField):
1832    description = "Positive integer"
1833
1834    def get_internal_type(self) -> str:
1835        return "PositiveIntegerField"
1836
1837
1838class PositiveSmallIntegerField(PositiveIntegerRelDbTypeMixin, SmallIntegerField):
1839    description = "Positive small integer"
1840
1841    def get_internal_type(self) -> str:
1842        return "PositiveSmallIntegerField"
1843
1844
1845class TextField(Field[str]):
1846    description = "Text"
1847
1848    def get_internal_type(self) -> str:
1849        return "TextField"
1850
1851    def to_python(self, value: Any) -> str | None:
1852        if isinstance(value, str) or value is None:
1853            return value
1854        return str(value)
1855
1856    def get_prep_value(self, value: Any) -> Any:
1857        value = super().get_prep_value(value)
1858        return self.to_python(value)
1859
1860
1861class TimeField(DateTimeCheckMixin, Field[datetime.time]):
1862    empty_strings_allowed = False
1863    default_error_messages = {
1864        "invalid": '"%(value)s" value has an invalid format. It must be in HH:MM[:ss[.uuuuuu]] format.',
1865        "invalid_time": '"%(value)s" value has the correct format (HH:MM[:ss[.uuuuuu]]) but it is an invalid time.',
1866    }
1867    description = "Time"
1868
1869    def __init__(
1870        self, *, auto_now: bool = False, auto_now_add: bool = False, **kwargs: Any
1871    ):
1872        self.auto_now, self.auto_now_add = auto_now, auto_now_add
1873        if auto_now or auto_now_add:
1874            kwargs["required"] = False
1875        super().__init__(**kwargs)
1876
1877    def _check_fix_default_value(self) -> list[PreflightResult]:
1878        """
1879        Warn that using an actual date or datetime value is probably wrong;
1880        it's only evaluated on server startup.
1881        """
1882        if not self.has_default():
1883            return []
1884
1885        value = self.default
1886        if isinstance(value, datetime.datetime):
1887            now = None
1888        elif isinstance(value, datetime.time):
1889            now = _get_naive_now()
1890            # This will not use the right date in the race condition where now
1891            # is just before the date change and value is just past 0:00.
1892            value = datetime.datetime.combine(now.date(), value)
1893        else:
1894            # No explicit time / datetime value -- no checks necessary
1895            return []
1896        # At this point, value is a datetime object.
1897        return self._check_if_value_fixed(value, now=now)
1898
1899    def deconstruct(self) -> tuple[str | None, str, list[Any], dict[str, Any]]:
1900        name, path, args, kwargs = super().deconstruct()
1901        if self.auto_now is not False:
1902            kwargs["auto_now"] = self.auto_now
1903        if self.auto_now_add is not False:
1904            kwargs["auto_now_add"] = self.auto_now_add
1905        if self.auto_now or self.auto_now_add:
1906            del kwargs["required"]
1907        return name, path, args, kwargs
1908
1909    def get_internal_type(self) -> str:
1910        return "TimeField"
1911
1912    def to_python(self, value: Any) -> datetime.time | None:
1913        if value is None:
1914            return None
1915        if isinstance(value, datetime.time):
1916            return value
1917        if isinstance(value, datetime.datetime):
1918            # Not usually a good idea to pass in a datetime here (it loses
1919            # information), but we'll be accommodating.
1920            return value.time()
1921
1922        try:
1923            parsed = parse_time(value)
1924            if parsed is not None:
1925                return parsed
1926        except ValueError:
1927            raise exceptions.ValidationError(
1928                self.error_messages["invalid_time"],
1929                code="invalid_time",
1930                params={"value": value},
1931            )
1932
1933        raise exceptions.ValidationError(
1934            self.error_messages["invalid"],
1935            code="invalid",
1936            params={"value": value},
1937        )
1938
1939    def pre_save(self, model_instance: Model, add: bool) -> datetime.time | None:
1940        if self.auto_now or (self.auto_now_add and add):
1941            value = datetime.datetime.now().time()
1942            setattr(model_instance, self.attname, value)
1943            return value
1944        else:
1945            return super().pre_save(model_instance, add)
1946
1947    def get_prep_value(self, value: Any) -> Any:
1948        value = super().get_prep_value(value)
1949        return self.to_python(value)
1950
1951    def get_db_prep_value(
1952        self, value: Any, connection: DatabaseWrapper, prepared: bool = False
1953    ) -> Any:
1954        if not prepared:
1955            value = self.get_prep_value(value)
1956        return value
1957
1958    def value_to_string(self, obj: Model) -> str:
1959        val = self.value_from_object(obj)
1960        return "" if val is None else val.isoformat()
1961
1962
1963class URLField(CharField):
1964    default_validators = [validators.URLValidator()]
1965    description = "URL"
1966
1967    def __init__(self, **kwargs: Any):
1968        kwargs.setdefault("max_length", 200)
1969        super().__init__(**kwargs)
1970
1971    def deconstruct(self) -> tuple[str | None, str, list[Any], dict[str, Any]]:
1972        name, path, args, kwargs = super().deconstruct()
1973        if kwargs.get("max_length") == 200:
1974            del kwargs["max_length"]
1975        return name, path, args, kwargs
1976
1977
1978class BinaryField(Field[bytes | memoryview]):
1979    description = "Raw binary data"
1980    empty_values = [None, b""]
1981
1982    def __init__(self, **kwargs: Any):
1983        super().__init__(**kwargs)
1984        if self.max_length is not None:
1985            self.validators.append(validators.MaxLengthValidator(self.max_length))
1986
1987    def preflight(self, **kwargs: Any) -> list[PreflightResult]:
1988        return [*super().preflight(**kwargs), *self._check_str_default_value()]
1989
1990    def _check_str_default_value(self) -> list[PreflightResult]:
1991        if self.has_default() and isinstance(self.default, str):
1992            return [
1993                PreflightResult(
1994                    fix="BinaryField's default cannot be a string. Use bytes "
1995                    "content instead.",
1996                    obj=self,
1997                    id="fields.filefield_upload_to_not_callable",
1998                )
1999            ]
2000        return []
2001
2002    def get_internal_type(self) -> str:
2003        return "BinaryField"
2004
2005    def get_placeholder(
2006        self, value: Any, compiler: SQLCompiler, connection: DatabaseWrapper
2007    ) -> Any:
2008        return "%s"
2009
2010    def get_default(self) -> bytes | memoryview | None:
2011        if self.has_default() and not callable(self.default):
2012            return self.default
2013        default = super().get_default()
2014        if default == "":
2015            return b""
2016        return default
2017
2018    def get_db_prep_value(
2019        self, value: Any, connection: DatabaseWrapper, prepared: bool = False
2020    ) -> Any:
2021        value = super().get_db_prep_value(value, connection, prepared)
2022        if value is not None:
2023            return psycopg.Binary(value)
2024        return value
2025
2026    def value_to_string(self, obj: Model) -> str:
2027        """Binary data is serialized as base64"""
2028        val = self.value_from_object(obj)
2029        if val is None:
2030            return ""
2031        return b64encode(val).decode("ascii")
2032
2033    def to_python(self, value: Any) -> bytes | memoryview | None:
2034        # If it's a string, it should be base64-encoded data
2035        if isinstance(value, str):
2036            return memoryview(b64decode(value.encode("ascii")))
2037        return value
2038
2039
2040class UUIDField(Field[uuid.UUID]):
2041    default_error_messages = {
2042        "invalid": '"%(value)s" is not a valid UUID.',
2043    }
2044    description = "Universally unique identifier"
2045    empty_strings_allowed = False
2046
2047    def __init__(self, **kwargs: Any):
2048        kwargs["max_length"] = 32
2049        super().__init__(**kwargs)
2050
2051    def deconstruct(self) -> tuple[str | None, str, list[Any], dict[str, Any]]:
2052        name, path, args, kwargs = super().deconstruct()
2053        del kwargs["max_length"]
2054        return name, path, args, kwargs
2055
2056    def get_internal_type(self) -> str:
2057        return "UUIDField"
2058
2059    def get_prep_value(self, value: Any) -> Any:
2060        value = super().get_prep_value(value)
2061        return self.to_python(value)
2062
2063    def get_db_prep_value(
2064        self, value: Any, connection: DatabaseWrapper, prepared: bool = False
2065    ) -> uuid.UUID | None:
2066        # PostgreSQL has native UUID type
2067        if value is None:
2068            return None
2069        if not isinstance(value, uuid.UUID):
2070            value = self.to_python(value)
2071        return value
2072
2073    def to_python(self, value: Any) -> uuid.UUID | None:
2074        if value is not None and not isinstance(value, uuid.UUID):
2075            input_form = "int" if isinstance(value, int) else "hex"
2076            try:
2077                return uuid.UUID(**{input_form: value})
2078            except (AttributeError, ValueError):
2079                raise exceptions.ValidationError(
2080                    self.error_messages["invalid"],
2081                    code="invalid",
2082                    params={"value": value},
2083                )
2084        return value
2085
2086
2087class PrimaryKeyField(BigIntegerField):
2088    db_returning = True
2089
2090    def __init__(self):
2091        super().__init__(required=False)
2092        self.primary_key = True
2093        self.auto_created = True
2094
2095    def preflight(self, **kwargs: Any) -> list[PreflightResult]:
2096        errors = super().preflight(**kwargs)
2097        # Remove the reserved_field_name_id error for 'id' field name since PrimaryKeyField is allowed to use it
2098        errors = [e for e in errors if e.id != "fields.reserved_field_name_id"]
2099        return errors
2100
2101    def deconstruct(self) -> tuple[str | None, str, list[Any], dict[str, Any]]:
2102        # PrimaryKeyField takes no parameters, so we return an empty kwargs dict
2103        return (
2104            self.name,
2105            "plain.models.PrimaryKeyField",
2106            cast(list[Any], []),
2107            cast(dict[str, Any], {}),
2108        )
2109
2110    def validate(self, value: Any, model_instance: Model) -> None:
2111        pass
2112
2113    def get_db_prep_value(
2114        self, value: Any, connection: DatabaseWrapper, prepared: bool = False
2115    ) -> Any:
2116        if not prepared:
2117            value = self.get_prep_value(value)
2118        return value
2119
2120    def get_internal_type(self) -> str:
2121        return "PrimaryKeyField"
2122
2123    def rel_db_type(self) -> str | None:
2124        return BigIntegerField().db_type()