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