Plain is headed towards 1.0! Subscribe for development updates →

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