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