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

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