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)