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