Plain is headed towards 1.0! Subscribe for development updates โ†’

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