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