summaryrefslogtreecommitdiff
path: root/django/db/models/fields/__init__.py
diff options
context:
space:
mode:
Diffstat (limited to 'django/db/models/fields/__init__.py')
-rw-r--r--django/db/models/fields/__init__.py1094
1 files changed, 650 insertions, 444 deletions
diff --git a/django/db/models/fields/__init__.py b/django/db/models/fields/__init__.py
index 6d6d10a483..313e31b5f5 100644
--- a/django/db/models/fields/__init__.py
+++ b/django/db/models/fields/__init__.py
@@ -19,7 +19,10 @@ from django.db.models.query_utils import DeferredAttribute, RegisterLookupMixin
from django.utils import timezone
from django.utils.datastructures import DictWrapper
from django.utils.dateparse import (
- parse_date, parse_datetime, parse_duration, parse_time,
+ parse_date,
+ parse_datetime,
+ parse_duration,
+ parse_time,
)
from django.utils.duration import duration_microseconds, duration_string
from django.utils.functional import Promise, cached_property
@@ -29,14 +32,38 @@ from django.utils.text import capfirst
from django.utils.translation import gettext_lazy as _
__all__ = [
- 'AutoField', 'BLANK_CHOICE_DASH', 'BigAutoField', 'BigIntegerField',
- 'BinaryField', 'BooleanField', 'CharField', 'CommaSeparatedIntegerField',
- 'DateField', 'DateTimeField', 'DecimalField', 'DurationField',
- 'EmailField', 'Empty', 'Field', 'FilePathField', 'FloatField',
- 'GenericIPAddressField', 'IPAddressField', 'IntegerField', 'NOT_PROVIDED',
- 'NullBooleanField', 'PositiveBigIntegerField', 'PositiveIntegerField',
- 'PositiveSmallIntegerField', 'SlugField', 'SmallAutoField',
- 'SmallIntegerField', 'TextField', 'TimeField', 'URLField', 'UUIDField',
+ "AutoField",
+ "BLANK_CHOICE_DASH",
+ "BigAutoField",
+ "BigIntegerField",
+ "BinaryField",
+ "BooleanField",
+ "CharField",
+ "CommaSeparatedIntegerField",
+ "DateField",
+ "DateTimeField",
+ "DecimalField",
+ "DurationField",
+ "EmailField",
+ "Empty",
+ "Field",
+ "FilePathField",
+ "FloatField",
+ "GenericIPAddressField",
+ "IPAddressField",
+ "IntegerField",
+ "NOT_PROVIDED",
+ "NullBooleanField",
+ "PositiveBigIntegerField",
+ "PositiveIntegerField",
+ "PositiveSmallIntegerField",
+ "SlugField",
+ "SmallAutoField",
+ "SmallIntegerField",
+ "TextField",
+ "TimeField",
+ "URLField",
+ "UUIDField",
]
@@ -72,6 +99,7 @@ def _load_field(app_label, model_name, field_name):
#
# getattr(obj, opts.pk.attname)
+
def _empty(of_cls):
new = Empty()
new.__class__ = of_cls
@@ -98,14 +126,16 @@ class Field(RegisterLookupMixin):
auto_creation_counter = -1
default_validators = [] # Default set of validators
default_error_messages = {
- 'invalid_choice': _('Value %(value)r is not a valid choice.'),
- 'null': _('This field cannot be null.'),
- 'blank': _('This field cannot be blank.'),
- 'unique': _('%(model_name)s with this %(field_label)s already exists.'),
+ "invalid_choice": _("Value %(value)r is not a valid choice."),
+ "null": _("This field cannot be null."),
+ "blank": _("This field cannot be blank."),
+ "unique": _("%(model_name)s with this %(field_label)s already exists."),
# Translators: The 'lookup_type' is one of 'date', 'year' or 'month'.
# Eg: "Title must be unique for pub_date year"
- 'unique_for_date': _("%(field_label)s must be unique for "
- "%(date_field_label)s %(lookup_type)s."),
+ "unique_for_date": _(
+ "%(field_label)s must be unique for "
+ "%(date_field_label)s %(lookup_type)s."
+ ),
}
system_check_deprecated_details = None
system_check_removed_details = None
@@ -123,18 +153,37 @@ class Field(RegisterLookupMixin):
# Generic field type description, usually overridden by subclasses
def _description(self):
- return _('Field of type: %(field_type)s') % {
- 'field_type': self.__class__.__name__
+ return _("Field of type: %(field_type)s") % {
+ "field_type": self.__class__.__name__
}
+
description = property(_description)
- def __init__(self, verbose_name=None, name=None, primary_key=False,
- max_length=None, unique=False, blank=False, null=False,
- db_index=False, rel=None, default=NOT_PROVIDED, editable=True,
- serialize=True, unique_for_date=None, unique_for_month=None,
- unique_for_year=None, choices=None, help_text='', db_column=None,
- db_tablespace=None, auto_created=False, validators=(),
- error_messages=None):
+ def __init__(
+ self,
+ verbose_name=None,
+ name=None,
+ primary_key=False,
+ max_length=None,
+ unique=False,
+ blank=False,
+ null=False,
+ db_index=False,
+ rel=None,
+ default=NOT_PROVIDED,
+ editable=True,
+ serialize=True,
+ unique_for_date=None,
+ unique_for_month=None,
+ unique_for_year=None,
+ choices=None,
+ help_text="",
+ db_column=None,
+ db_tablespace=None,
+ auto_created=False,
+ validators=(),
+ error_messages=None,
+ ):
self.name = name
self.verbose_name = verbose_name # May be set by set_attributes_from_name
self._verbose_name = verbose_name # Store original for deconstruction
@@ -170,7 +219,7 @@ class Field(RegisterLookupMixin):
messages = {}
for c in reversed(self.__class__.__mro__):
- messages.update(getattr(c, 'default_error_messages', {}))
+ messages.update(getattr(c, "default_error_messages", {}))
messages.update(error_messages or {})
self._error_messages = error_messages # Store for deconstruction later
self.error_messages = messages
@@ -180,18 +229,18 @@ class Field(RegisterLookupMixin):
Return "app_label.model_label.field_name" for fields attached to
models.
"""
- if not hasattr(self, 'model'):
+ if not hasattr(self, "model"):
return super().__str__()
model = self.model
- return '%s.%s' % (model._meta.label, self.name)
+ return "%s.%s" % (model._meta.label, self.name)
def __repr__(self):
"""Display the module, class, and name of the field."""
- path = '%s.%s' % (self.__class__.__module__, self.__class__.__qualname__)
- name = getattr(self, 'name', None)
+ path = "%s.%s" % (self.__class__.__module__, self.__class__.__qualname__)
+ name = getattr(self, "name", None)
if name is not None:
- return '<%s: %s>' % (path, name)
- return '<%s>' % path
+ return "<%s: %s>" % (path, name)
+ return "<%s>" % path
def check(self, **kwargs):
return [
@@ -209,12 +258,12 @@ class Field(RegisterLookupMixin):
Check if field name is valid, i.e. 1) does not end with an
underscore, 2) does not contain "__" and 3) is not "pk".
"""
- if self.name.endswith('_'):
+ if self.name.endswith("_"):
return [
checks.Error(
- 'Field names must not end with an underscore.',
+ "Field names must not end with an underscore.",
obj=self,
- id='fields.E001',
+ id="fields.E001",
)
]
elif LOOKUP_SEP in self.name:
@@ -222,15 +271,15 @@ class Field(RegisterLookupMixin):
checks.Error(
'Field names must not contain "%s".' % LOOKUP_SEP,
obj=self,
- id='fields.E002',
+ id="fields.E002",
)
]
- elif self.name == 'pk':
+ elif self.name == "pk":
return [
checks.Error(
"'pk' is a reserved word that cannot be used as a field name.",
obj=self,
- id='fields.E003',
+ id="fields.E003",
)
]
else:
@@ -249,7 +298,7 @@ class Field(RegisterLookupMixin):
checks.Error(
"'choices' must be an iterable (e.g., a list or tuple).",
obj=self,
- id='fields.E004',
+ id="fields.E004",
)
]
@@ -268,14 +317,22 @@ class Field(RegisterLookupMixin):
):
break
if self.max_length is not None and group_choices:
- choice_max_length = max([
- choice_max_length,
- *(len(value) for value, _ in group_choices if isinstance(value, str)),
- ])
+ choice_max_length = max(
+ [
+ choice_max_length,
+ *(
+ len(value)
+ for value, _ in group_choices
+ if isinstance(value, str)
+ ),
+ ]
+ )
except (TypeError, ValueError):
# No groups, choices in the form [value, display]
value, human_name = group_name, group_choices
- if not self._choices_is_value(value) or not self._choices_is_value(human_name):
+ if not self._choices_is_value(value) or not self._choices_is_value(
+ human_name
+ ):
break
if self.max_length is not None and isinstance(value, str):
choice_max_length = max(choice_max_length, len(value))
@@ -290,7 +347,7 @@ class Field(RegisterLookupMixin):
"'max_length' is too small to fit the longest value "
"in 'choices' (%d characters)." % choice_max_length,
obj=self,
- id='fields.E009',
+ id="fields.E009",
),
]
return []
@@ -300,7 +357,7 @@ class Field(RegisterLookupMixin):
"'choices' must be an iterable containing "
"(actual value, human readable name) tuples.",
obj=self,
- id='fields.E005',
+ id="fields.E005",
)
]
@@ -310,25 +367,30 @@ class Field(RegisterLookupMixin):
checks.Error(
"'db_index' must be None, True or False.",
obj=self,
- id='fields.E006',
+ id="fields.E006",
)
]
else:
return []
def _check_null_allowed_for_primary_keys(self):
- if (self.primary_key and self.null and
- not connection.features.interprets_empty_strings_as_nulls):
+ if (
+ self.primary_key
+ and self.null
+ and not connection.features.interprets_empty_strings_as_nulls
+ ):
# We cannot reliably check this for backends like Oracle which
# consider NULL and '' to be equal (and thus set up
# character-based fields a little differently).
return [
checks.Error(
- 'Primary keys must not have null=True.',
- hint=('Set null=False on the field, or '
- 'remove primary_key=True argument.'),
+ "Primary keys must not have null=True.",
+ hint=(
+ "Set null=False on the field, or "
+ "remove primary_key=True argument."
+ ),
obj=self,
- id='fields.E007',
+ id="fields.E007",
)
]
else:
@@ -340,7 +402,9 @@ class Field(RegisterLookupMixin):
app_label = self.model._meta.app_label
errors = []
for alias in databases:
- if router.allow_migrate(alias, app_label, model_name=self.model._meta.model_name):
+ if router.allow_migrate(
+ alias, app_label, model_name=self.model._meta.model_name
+ ):
errors.extend(connections[alias].validation.check_field(self, **kwargs))
return errors
@@ -354,11 +418,12 @@ class Field(RegisterLookupMixin):
hint=(
"validators[{i}] ({repr}) isn't a function or "
"instance of a validator class.".format(
- i=i, repr=repr(validator),
+ i=i,
+ repr=repr(validator),
)
),
obj=self,
- id='fields.E008',
+ id="fields.E008",
)
)
return errors
@@ -368,41 +433,41 @@ class Field(RegisterLookupMixin):
return [
checks.Error(
self.system_check_removed_details.get(
- 'msg',
- '%s has been removed except for support in historical '
- 'migrations.' % self.__class__.__name__
+ "msg",
+ "%s has been removed except for support in historical "
+ "migrations." % self.__class__.__name__,
),
- hint=self.system_check_removed_details.get('hint'),
+ hint=self.system_check_removed_details.get("hint"),
obj=self,
- id=self.system_check_removed_details.get('id', 'fields.EXXX'),
+ id=self.system_check_removed_details.get("id", "fields.EXXX"),
)
]
elif self.system_check_deprecated_details is not None:
return [
checks.Warning(
self.system_check_deprecated_details.get(
- 'msg',
- '%s has been deprecated.' % self.__class__.__name__
+ "msg", "%s has been deprecated." % self.__class__.__name__
),
- hint=self.system_check_deprecated_details.get('hint'),
+ hint=self.system_check_deprecated_details.get("hint"),
obj=self,
- id=self.system_check_deprecated_details.get('id', 'fields.WXXX'),
+ id=self.system_check_deprecated_details.get("id", "fields.WXXX"),
)
]
return []
def get_col(self, alias, output_field=None):
- if (
- alias == self.model._meta.db_table and
- (output_field is None or output_field == self)
+ if alias == self.model._meta.db_table and (
+ output_field is None or output_field == self
):
return self.cached_col
from django.db.models.expressions import Col
+
return Col(alias, self, output_field)
@cached_property
def cached_col(self):
from django.db.models.expressions import Col
+
return Col(self.model._meta.db_table, self)
def select_format(self, compiler, sql, params):
@@ -462,7 +527,7 @@ class Field(RegisterLookupMixin):
"unique_for_month": None,
"unique_for_year": None,
"choices": None,
- "help_text": '',
+ "help_text": "",
"db_column": None,
"db_tablespace": None,
"auto_created": False,
@@ -495,8 +560,8 @@ class Field(RegisterLookupMixin):
path = path.replace("django.db.models.fields.related", "django.db.models")
elif path.startswith("django.db.models.fields.files"):
path = path.replace("django.db.models.fields.files", "django.db.models")
- elif path.startswith('django.db.models.fields.json'):
- path = path.replace('django.db.models.fields.json', 'django.db.models')
+ elif path.startswith("django.db.models.fields.json"):
+ path = path.replace("django.db.models.fields.json", "django.db.models")
elif path.startswith("django.db.models.fields.proxy"):
path = path.replace("django.db.models.fields.proxy", "django.db.models")
elif path.startswith("django.db.models.fields"):
@@ -515,10 +580,9 @@ class Field(RegisterLookupMixin):
def __eq__(self, other):
# Needed for @total_ordering
if isinstance(other, Field):
- return (
- self.creation_counter == other.creation_counter and
- getattr(self, 'model', None) == getattr(other, 'model', None)
- )
+ return self.creation_counter == other.creation_counter and getattr(
+ self, "model", None
+ ) == getattr(other, "model", None)
return NotImplemented
def __lt__(self, other):
@@ -526,17 +590,18 @@ class Field(RegisterLookupMixin):
# Order by creation_counter first for backward compatibility.
if isinstance(other, Field):
if (
- self.creation_counter != other.creation_counter or
- not hasattr(self, 'model') and not hasattr(other, 'model')
+ self.creation_counter != other.creation_counter
+ or not hasattr(self, "model")
+ and not hasattr(other, "model")
):
return self.creation_counter < other.creation_counter
- elif hasattr(self, 'model') != hasattr(other, 'model'):
- return not hasattr(self, 'model') # Order no-model fields first
+ elif hasattr(self, "model") != hasattr(other, "model"):
+ return not hasattr(self, "model") # Order no-model fields first
else:
# creation_counter's are equal, compare only models.
- return (
- (self.model._meta.app_label, self.model._meta.model_name) <
- (other.model._meta.app_label, other.model._meta.model_name)
+ return (self.model._meta.app_label, self.model._meta.model_name) < (
+ other.model._meta.app_label,
+ other.model._meta.model_name,
)
return NotImplemented
@@ -549,7 +614,7 @@ class Field(RegisterLookupMixin):
obj = copy.copy(self)
if self.remote_field:
obj.remote_field = copy.copy(self.remote_field)
- if hasattr(self.remote_field, 'field') and self.remote_field.field is self:
+ if hasattr(self.remote_field, "field") and self.remote_field.field is self:
obj.remote_field.field = obj
memodict[id(self)] = obj
return obj
@@ -568,7 +633,7 @@ class Field(RegisterLookupMixin):
not a new copy of that field. So, use the app registry to load the
model and then the field back.
"""
- if not hasattr(self, 'model'):
+ if not hasattr(self, "model"):
# Fields are sometimes used without attaching them to models (for
# example in aggregation). In this case give back a plain field
# instance. The code below will create a new empty instance of
@@ -577,10 +642,13 @@ class Field(RegisterLookupMixin):
state = self.__dict__.copy()
# The _get_default cached_property can't be pickled due to lambda
# usage.
- state.pop('_get_default', None)
+ state.pop("_get_default", None)
return _empty, (self.__class__,), state
- return _load_field, (self.model._meta.app_label, self.model._meta.object_name,
- self.name)
+ return _load_field, (
+ self.model._meta.app_label,
+ self.model._meta.object_name,
+ self.name,
+ )
def get_pk_value_on_save(self, instance):
"""
@@ -618,7 +686,7 @@ class Field(RegisterLookupMixin):
try:
v(value)
except exceptions.ValidationError as e:
- if hasattr(e, 'code') and e.code in self.error_messages:
+ if hasattr(e, "code") and e.code in self.error_messages:
e.message = self.error_messages[e.code]
errors.extend(e.error_list)
@@ -645,16 +713,16 @@ class Field(RegisterLookupMixin):
elif value == option_key:
return
raise exceptions.ValidationError(
- self.error_messages['invalid_choice'],
- code='invalid_choice',
- params={'value': value},
+ self.error_messages["invalid_choice"],
+ code="invalid_choice",
+ params={"value": value},
)
if value is None and not self.null:
- raise exceptions.ValidationError(self.error_messages['null'], code='null')
+ raise exceptions.ValidationError(self.error_messages["null"], code="null")
if not self.blank and value in self.empty_values:
- raise exceptions.ValidationError(self.error_messages['blank'], code='blank')
+ raise exceptions.ValidationError(self.error_messages["blank"], code="blank")
def clean(self, value, model_instance):
"""
@@ -668,7 +736,7 @@ class Field(RegisterLookupMixin):
return value
def db_type_parameters(self, connection):
- return DictWrapper(self.__dict__, connection.ops.quote_name, 'qn_')
+ return DictWrapper(self.__dict__, connection.ops.quote_name, "qn_")
def db_check(self, connection):
"""
@@ -678,7 +746,9 @@ class Field(RegisterLookupMixin):
"""
data = self.db_type_parameters(connection)
try:
- return connection.data_type_check_constraints[self.get_internal_type()] % data
+ return (
+ connection.data_type_check_constraints[self.get_internal_type()] % data
+ )
except KeyError:
return None
@@ -740,7 +810,7 @@ class Field(RegisterLookupMixin):
return connection.data_types_suffix.get(self.get_internal_type())
def get_db_converters(self, connection):
- if hasattr(self, 'from_db_value'):
+ if hasattr(self, "from_db_value"):
return [self.from_db_value]
return []
@@ -765,7 +835,7 @@ class Field(RegisterLookupMixin):
self.attname, self.column = self.get_attname_column()
self.concrete = self.column is not None
if self.verbose_name is None and self.name:
- self.verbose_name = self.name.replace('_', ' ')
+ self.verbose_name = self.name.replace("_", " ")
def contribute_to_class(self, cls, name, private_only=False):
"""
@@ -784,10 +854,10 @@ class Field(RegisterLookupMixin):
# this class, but don't check methods derived from inheritance, to
# allow overriding inherited choices. For more complex inheritance
# structures users should override contribute_to_class().
- if 'get_%s_display' % self.name not in cls.__dict__:
+ if "get_%s_display" % self.name not in cls.__dict__:
setattr(
cls,
- 'get_%s_display' % self.name,
+ "get_%s_display" % self.name,
partialmethod(cls._get_FIELD_display, field=self),
)
@@ -848,11 +918,21 @@ class Field(RegisterLookupMixin):
return self.default
return lambda: self.default
- if not self.empty_strings_allowed or self.null and not connection.features.interprets_empty_strings_as_nulls:
+ if (
+ not self.empty_strings_allowed
+ or self.null
+ and not connection.features.interprets_empty_strings_as_nulls
+ ):
return return_None
return str # return empty string
- def get_choices(self, include_blank=True, blank_choice=BLANK_CHOICE_DASH, limit_choices_to=None, ordering=()):
+ def get_choices(
+ self,
+ include_blank=True,
+ blank_choice=BLANK_CHOICE_DASH,
+ limit_choices_to=None,
+ ordering=(),
+ ):
"""
Return choices with a default blank choices included, for use
as <select> choices for this field.
@@ -860,7 +940,9 @@ class Field(RegisterLookupMixin):
if self.choices is not None:
choices = list(self.choices)
if include_blank:
- blank_defined = any(choice in ('', None) for choice, _ in self.flatchoices)
+ blank_defined = any(
+ choice in ("", None) for choice, _ in self.flatchoices
+ )
if not blank_defined:
choices = blank_choice + choices
return choices
@@ -868,8 +950,8 @@ class Field(RegisterLookupMixin):
limit_choices_to = limit_choices_to or self.get_limit_choices_to()
choice_func = operator.attrgetter(
self.remote_field.get_related_field().attname
- if hasattr(self.remote_field, 'get_related_field')
- else 'pk'
+ if hasattr(self.remote_field, "get_related_field")
+ else "pk"
)
qs = rel_model._default_manager.complex_filter(limit_choices_to)
if ordering:
@@ -896,6 +978,7 @@ class Field(RegisterLookupMixin):
else:
flat.append((choice, value))
return flat
+
flatchoices = property(_get_flatchoices)
def save_form_data(self, instance, data):
@@ -904,24 +987,25 @@ class Field(RegisterLookupMixin):
def formfield(self, form_class=None, choices_form_class=None, **kwargs):
"""Return a django.forms.Field instance for this field."""
defaults = {
- 'required': not self.blank,
- 'label': capfirst(self.verbose_name),
- 'help_text': self.help_text,
+ "required": not self.blank,
+ "label": capfirst(self.verbose_name),
+ "help_text": self.help_text,
}
if self.has_default():
if callable(self.default):
- defaults['initial'] = self.default
- defaults['show_hidden_initial'] = True
+ defaults["initial"] = self.default
+ defaults["show_hidden_initial"] = True
else:
- defaults['initial'] = self.get_default()
+ defaults["initial"] = self.get_default()
if self.choices is not None:
# Fields with choices get special treatment.
- include_blank = (self.blank or
- not (self.has_default() or 'initial' in kwargs))
- defaults['choices'] = self.get_choices(include_blank=include_blank)
- defaults['coerce'] = self.to_python
+ include_blank = self.blank or not (
+ self.has_default() or "initial" in kwargs
+ )
+ defaults["choices"] = self.get_choices(include_blank=include_blank)
+ defaults["coerce"] = self.to_python
if self.null:
- defaults['empty_value'] = None
+ defaults["empty_value"] = None
if choices_form_class is not None:
form_class = choices_form_class
else:
@@ -930,9 +1014,19 @@ class Field(RegisterLookupMixin):
# max_value) don't apply for choice fields, so be sure to only pass
# the values that TypedChoiceField will understand.
for k in list(kwargs):
- if k not in ('coerce', 'empty_value', 'choices', 'required',
- 'widget', 'label', 'initial', 'help_text',
- 'error_messages', 'show_hidden_initial', 'disabled'):
+ if k not in (
+ "coerce",
+ "empty_value",
+ "choices",
+ "required",
+ "widget",
+ "label",
+ "initial",
+ "help_text",
+ "error_messages",
+ "show_hidden_initial",
+ "disabled",
+ ):
del kwargs[k]
defaults.update(kwargs)
if form_class is None:
@@ -947,8 +1041,8 @@ class Field(RegisterLookupMixin):
class BooleanField(Field):
empty_strings_allowed = False
default_error_messages = {
- 'invalid': _('“%(value)s” value must be either True or False.'),
- 'invalid_nullable': _('“%(value)s” value must be either True, False, or None.'),
+ "invalid": _("“%(value)s” value must be either True or False."),
+ "invalid_nullable": _("“%(value)s” value must be either True, False, or None."),
}
description = _("Boolean (Either True or False)")
@@ -961,14 +1055,14 @@ class BooleanField(Field):
if value in (True, False):
# 1/0 are equal to True/False. bool() converts former to latter.
return bool(value)
- if value in ('t', 'True', '1'):
+ if value in ("t", "True", "1"):
return True
- if value in ('f', 'False', '0'):
+ if value in ("f", "False", "0"):
return False
raise exceptions.ValidationError(
- self.error_messages['invalid_nullable' if self.null else 'invalid'],
- code='invalid',
- params={'value': value},
+ self.error_messages["invalid_nullable" if self.null else "invalid"],
+ code="invalid",
+ params={"value": value},
)
def get_prep_value(self, value):
@@ -979,14 +1073,14 @@ class BooleanField(Field):
def formfield(self, **kwargs):
if self.choices is not None:
- include_blank = not (self.has_default() or 'initial' in kwargs)
- defaults = {'choices': self.get_choices(include_blank=include_blank)}
+ include_blank = not (self.has_default() or "initial" in kwargs)
+ defaults = {"choices": self.get_choices(include_blank=include_blank)}
else:
form_class = forms.NullBooleanField if self.null else forms.BooleanField
# In HTML checkboxes, 'required' means "must be checked" which is
# different from the choices case ("must select some value").
# required=False allows unchecked checkboxes.
- defaults = {'form_class': form_class, 'required': False}
+ defaults = {"form_class": form_class, "required": False}
return super().formfield(**{**defaults, **kwargs})
def select_format(self, compiler, sql, params):
@@ -994,8 +1088,8 @@ class BooleanField(Field):
# Filters that match everything are handled as empty strings in the
# WHERE clause, but in SELECT or GROUP BY list they must use a
# predicate that's always True.
- if sql == '':
- sql = '1'
+ if sql == "":
+ sql = "1"
return sql, params
@@ -1009,7 +1103,7 @@ class CharField(Field):
self.validators.append(validators.MaxLengthValidator(self.max_length))
def check(self, **kwargs):
- databases = kwargs.get('databases') or []
+ databases = kwargs.get("databases") or []
return [
*super().check(**kwargs),
*self._check_db_collation(databases),
@@ -1022,16 +1116,19 @@ class CharField(Field):
checks.Error(
"CharFields must define a 'max_length' attribute.",
obj=self,
- id='fields.E120',
+ id="fields.E120",
)
]
- elif (not isinstance(self.max_length, int) or isinstance(self.max_length, bool) or
- self.max_length <= 0):
+ elif (
+ not isinstance(self.max_length, int)
+ or isinstance(self.max_length, bool)
+ or self.max_length <= 0
+ ):
return [
checks.Error(
"'max_length' must be a positive integer.",
obj=self,
- id='fields.E121',
+ id="fields.E121",
)
]
else:
@@ -1044,16 +1141,17 @@ class CharField(Field):
continue
connection = connections[db]
if not (
- self.db_collation is None or
- 'supports_collation_on_charfield' in self.model._meta.required_db_features or
- connection.features.supports_collation_on_charfield
+ self.db_collation is None
+ or "supports_collation_on_charfield"
+ in self.model._meta.required_db_features
+ or connection.features.supports_collation_on_charfield
):
errors.append(
checks.Error(
- '%s does not support a database collation on '
- 'CharFields.' % connection.display_name,
+ "%s does not support a database collation on "
+ "CharFields." % connection.display_name,
obj=self,
- id='fields.E190',
+ id="fields.E190",
),
)
return errors
@@ -1079,17 +1177,17 @@ class CharField(Field):
# Passing max_length to forms.CharField means that the value's length
# will be validated twice. This is considered acceptable since we want
# the value in the form field (to pass into widget for example).
- defaults = {'max_length': self.max_length}
+ defaults = {"max_length": self.max_length}
# TODO: Handle multiple backends with different feature flags.
if self.null and not connection.features.interprets_empty_strings_as_nulls:
- defaults['empty_value'] = None
+ defaults["empty_value"] = None
defaults.update(kwargs)
return super().formfield(**defaults)
def deconstruct(self):
name, path, args, kwargs = super().deconstruct()
if self.db_collation:
- kwargs['db_collation'] = self.db_collation
+ kwargs["db_collation"] = self.db_collation
return name, path, args, kwargs
@@ -1097,15 +1195,15 @@ class CommaSeparatedIntegerField(CharField):
default_validators = [validators.validate_comma_separated_integer_list]
description = _("Comma-separated integers")
system_check_removed_details = {
- 'msg': (
- 'CommaSeparatedIntegerField is removed except for support in '
- 'historical migrations.'
+ "msg": (
+ "CommaSeparatedIntegerField is removed except for support in "
+ "historical migrations."
),
- 'hint': (
- 'Use CharField(validators=[validate_comma_separated_integer_list]) '
- 'instead.'
+ "hint": (
+ "Use CharField(validators=[validate_comma_separated_integer_list]) "
+ "instead."
),
- 'id': 'fields.E901',
+ "id": "fields.E901",
}
@@ -1120,7 +1218,6 @@ def _get_naive_now():
class DateTimeCheckMixin:
-
def check(self, **kwargs):
return [
*super().check(**kwargs),
@@ -1132,8 +1229,14 @@ class DateTimeCheckMixin:
# auto_now, auto_now_add, and default are mutually exclusive
# options. The use of more than one of these options together
# will trigger an Error
- mutually_exclusive_options = [self.auto_now_add, self.auto_now, self.has_default()]
- enabled_options = [option not in (None, False) for option in mutually_exclusive_options].count(True)
+ mutually_exclusive_options = [
+ self.auto_now_add,
+ self.auto_now,
+ self.has_default(),
+ ]
+ enabled_options = [
+ option not in (None, False) for option in mutually_exclusive_options
+ ].count(True)
if enabled_options > 1:
return [
checks.Error(
@@ -1141,7 +1244,7 @@ class DateTimeCheckMixin:
"are mutually exclusive. Only one of these options "
"may be present.",
obj=self,
- id='fields.E160',
+ id="fields.E160",
)
]
else:
@@ -1173,15 +1276,15 @@ class DateTimeCheckMixin:
if lower <= value <= upper:
return [
checks.Warning(
- 'Fixed default value provided.',
+ "Fixed default value provided.",
hint=(
- 'It seems you set a fixed date / time / datetime '
- 'value as default for this field. This may not be '
- 'what you want. If you want to have the current date '
- 'as default, use `django.utils.timezone.now`'
+ "It seems you set a fixed date / time / datetime "
+ "value as default for this field. This may not be "
+ "what you want. If you want to have the current date "
+ "as default, use `django.utils.timezone.now`"
),
obj=self,
- id='fields.W161',
+ id="fields.W161",
)
]
return []
@@ -1190,19 +1293,24 @@ class DateTimeCheckMixin:
class DateField(DateTimeCheckMixin, Field):
empty_strings_allowed = False
default_error_messages = {
- 'invalid': _('“%(value)s” value has an invalid date format. It must be '
- 'in YYYY-MM-DD format.'),
- 'invalid_date': _('“%(value)s” value has the correct format (YYYY-MM-DD) '
- 'but it is an invalid date.'),
+ "invalid": _(
+ "“%(value)s” value has an invalid date format. It must be "
+ "in YYYY-MM-DD format."
+ ),
+ "invalid_date": _(
+ "“%(value)s” value has the correct format (YYYY-MM-DD) "
+ "but it is an invalid date."
+ ),
}
description = _("Date (without time)")
- def __init__(self, verbose_name=None, name=None, auto_now=False,
- auto_now_add=False, **kwargs):
+ def __init__(
+ self, verbose_name=None, name=None, auto_now=False, auto_now_add=False, **kwargs
+ ):
self.auto_now, self.auto_now_add = auto_now, auto_now_add
if auto_now or auto_now_add:
- kwargs['editable'] = False
- kwargs['blank'] = True
+ kwargs["editable"] = False
+ kwargs["blank"] = True
super().__init__(verbose_name, name, **kwargs)
def _check_fix_default_value(self):
@@ -1227,12 +1335,12 @@ class DateField(DateTimeCheckMixin, Field):
def deconstruct(self):
name, path, args, kwargs = super().deconstruct()
if self.auto_now:
- kwargs['auto_now'] = True
+ kwargs["auto_now"] = True
if self.auto_now_add:
- kwargs['auto_now_add'] = True
+ kwargs["auto_now_add"] = True
if self.auto_now or self.auto_now_add:
- del kwargs['editable']
- del kwargs['blank']
+ del kwargs["editable"]
+ del kwargs["blank"]
return name, path, args, kwargs
def get_internal_type(self):
@@ -1257,15 +1365,15 @@ class DateField(DateTimeCheckMixin, Field):
return parsed
except ValueError:
raise exceptions.ValidationError(
- self.error_messages['invalid_date'],
- code='invalid_date',
- params={'value': value},
+ self.error_messages["invalid_date"],
+ code="invalid_date",
+ params={"value": value},
)
raise exceptions.ValidationError(
- self.error_messages['invalid'],
- code='invalid',
- params={'value': value},
+ self.error_messages["invalid"],
+ code="invalid",
+ params={"value": value},
)
def pre_save(self, model_instance, add):
@@ -1280,12 +1388,18 @@ class DateField(DateTimeCheckMixin, Field):
super().contribute_to_class(cls, name, **kwargs)
if not self.null:
setattr(
- cls, 'get_next_by_%s' % self.name,
- partialmethod(cls._get_next_or_previous_by_FIELD, field=self, is_next=True)
+ cls,
+ "get_next_by_%s" % self.name,
+ partialmethod(
+ cls._get_next_or_previous_by_FIELD, field=self, is_next=True
+ ),
)
setattr(
- cls, 'get_previous_by_%s' % self.name,
- partialmethod(cls._get_next_or_previous_by_FIELD, field=self, is_next=False)
+ cls,
+ "get_previous_by_%s" % self.name,
+ partialmethod(
+ cls._get_next_or_previous_by_FIELD, field=self, is_next=False
+ ),
)
def get_prep_value(self, value):
@@ -1300,25 +1414,33 @@ class DateField(DateTimeCheckMixin, Field):
def value_to_string(self, obj):
val = self.value_from_object(obj)
- return '' if val is None else val.isoformat()
+ return "" if val is None else val.isoformat()
def formfield(self, **kwargs):
- return super().formfield(**{
- 'form_class': forms.DateField,
- **kwargs,
- })
+ return super().formfield(
+ **{
+ "form_class": forms.DateField,
+ **kwargs,
+ }
+ )
class DateTimeField(DateField):
empty_strings_allowed = False
default_error_messages = {
- 'invalid': _('“%(value)s” value has an invalid format. It must be in '
- 'YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ] format.'),
- 'invalid_date': _("“%(value)s” value has the correct format "
- "(YYYY-MM-DD) but it is an invalid date."),
- 'invalid_datetime': _('“%(value)s” value has the correct format '
- '(YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ]) '
- 'but it is an invalid date/time.'),
+ "invalid": _(
+ "“%(value)s” value has an invalid format. It must be in "
+ "YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ] format."
+ ),
+ "invalid_date": _(
+ "“%(value)s” value has the correct format "
+ "(YYYY-MM-DD) but it is an invalid date."
+ ),
+ "invalid_datetime": _(
+ "“%(value)s” value has the correct format "
+ "(YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ]) "
+ "but it is an invalid date/time."
+ ),
}
description = _("Date (with time)")
@@ -1353,10 +1475,12 @@ class DateTimeField(DateField):
# local time. This won't work during DST change, but we can't
# do much about it, so we let the exceptions percolate up the
# call stack.
- warnings.warn("DateTimeField %s.%s received a naive datetime "
- "(%s) while time zone support is active." %
- (self.model.__name__, self.name, value),
- RuntimeWarning)
+ warnings.warn(
+ "DateTimeField %s.%s received a naive datetime "
+ "(%s) while time zone support is active."
+ % (self.model.__name__, self.name, value),
+ RuntimeWarning,
+ )
default_timezone = timezone.get_default_timezone()
value = timezone.make_aware(value, default_timezone)
return value
@@ -1367,9 +1491,9 @@ class DateTimeField(DateField):
return parsed
except ValueError:
raise exceptions.ValidationError(
- self.error_messages['invalid_datetime'],
- code='invalid_datetime',
- params={'value': value},
+ self.error_messages["invalid_datetime"],
+ code="invalid_datetime",
+ params={"value": value},
)
try:
@@ -1378,15 +1502,15 @@ class DateTimeField(DateField):
return datetime.datetime(parsed.year, parsed.month, parsed.day)
except ValueError:
raise exceptions.ValidationError(
- self.error_messages['invalid_date'],
- code='invalid_date',
- params={'value': value},
+ self.error_messages["invalid_date"],
+ code="invalid_date",
+ params={"value": value},
)
raise exceptions.ValidationError(
- self.error_messages['invalid'],
- code='invalid',
- params={'value': value},
+ self.error_messages["invalid"],
+ code="invalid",
+ params={"value": value},
)
def pre_save(self, model_instance, add):
@@ -1408,13 +1532,14 @@ class DateTimeField(DateField):
# time. This won't work during DST change, but we can't do much
# about it, so we let the exceptions percolate up the call stack.
try:
- name = '%s.%s' % (self.model.__name__, self.name)
+ name = "%s.%s" % (self.model.__name__, self.name)
except AttributeError:
- name = '(unbound)'
- warnings.warn("DateTimeField %s received a naive datetime (%s)"
- " while time zone support is active." %
- (name, value),
- RuntimeWarning)
+ name = "(unbound)"
+ warnings.warn(
+ "DateTimeField %s received a naive datetime (%s)"
+ " while time zone support is active." % (name, value),
+ RuntimeWarning,
+ )
default_timezone = timezone.get_default_timezone()
value = timezone.make_aware(value, default_timezone)
return value
@@ -1427,24 +1552,32 @@ class DateTimeField(DateField):
def value_to_string(self, obj):
val = self.value_from_object(obj)
- return '' if val is None else val.isoformat()
+ return "" if val is None else val.isoformat()
def formfield(self, **kwargs):
- return super().formfield(**{
- 'form_class': forms.DateTimeField,
- **kwargs,
- })
+ return super().formfield(
+ **{
+ "form_class": forms.DateTimeField,
+ **kwargs,
+ }
+ )
class DecimalField(Field):
empty_strings_allowed = False
default_error_messages = {
- 'invalid': _('“%(value)s” value must be a decimal number.'),
+ "invalid": _("“%(value)s” value must be a decimal number."),
}
description = _("Decimal number")
- def __init__(self, verbose_name=None, name=None, max_digits=None,
- decimal_places=None, **kwargs):
+ def __init__(
+ self,
+ verbose_name=None,
+ name=None,
+ max_digits=None,
+ decimal_places=None,
+ **kwargs,
+ ):
self.max_digits, self.decimal_places = max_digits, decimal_places
super().__init__(verbose_name, name, **kwargs)
@@ -1471,7 +1604,7 @@ class DecimalField(Field):
checks.Error(
"DecimalFields must define a 'decimal_places' attribute.",
obj=self,
- id='fields.E130',
+ id="fields.E130",
)
]
except ValueError:
@@ -1479,7 +1612,7 @@ class DecimalField(Field):
checks.Error(
"'decimal_places' must be a non-negative integer.",
obj=self,
- id='fields.E131',
+ id="fields.E131",
)
]
else:
@@ -1495,7 +1628,7 @@ class DecimalField(Field):
checks.Error(
"DecimalFields must define a 'max_digits' attribute.",
obj=self,
- id='fields.E132',
+ id="fields.E132",
)
]
except ValueError:
@@ -1503,7 +1636,7 @@ class DecimalField(Field):
checks.Error(
"'max_digits' must be a positive integer.",
obj=self,
- id='fields.E133',
+ id="fields.E133",
)
]
else:
@@ -1515,7 +1648,7 @@ class DecimalField(Field):
checks.Error(
"'max_digits' must be greater or equal to 'decimal_places'.",
obj=self,
- id='fields.E134',
+ id="fields.E134",
)
]
return []
@@ -1533,9 +1666,9 @@ class DecimalField(Field):
def deconstruct(self):
name, path, args, kwargs = super().deconstruct()
if self.max_digits is not None:
- kwargs['max_digits'] = self.max_digits
+ kwargs["max_digits"] = self.max_digits
if self.decimal_places is not None:
- kwargs['decimal_places'] = self.decimal_places
+ kwargs["decimal_places"] = self.decimal_places
return name, path, args, kwargs
def get_internal_type(self):
@@ -1547,34 +1680,38 @@ class DecimalField(Field):
if isinstance(value, float):
if math.isnan(value):
raise exceptions.ValidationError(
- self.error_messages['invalid'],
- code='invalid',
- params={'value': value},
+ self.error_messages["invalid"],
+ code="invalid",
+ params={"value": value},
)
return self.context.create_decimal_from_float(value)
try:
return decimal.Decimal(value)
except (decimal.InvalidOperation, TypeError, ValueError):
raise exceptions.ValidationError(
- self.error_messages['invalid'],
- code='invalid',
- params={'value': value},
+ self.error_messages["invalid"],
+ code="invalid",
+ params={"value": value},
)
def get_db_prep_save(self, value, connection):
- return connection.ops.adapt_decimalfield_value(self.to_python(value), self.max_digits, self.decimal_places)
+ return connection.ops.adapt_decimalfield_value(
+ self.to_python(value), self.max_digits, self.decimal_places
+ )
def get_prep_value(self, value):
value = super().get_prep_value(value)
return self.to_python(value)
def formfield(self, **kwargs):
- return super().formfield(**{
- 'max_digits': self.max_digits,
- 'decimal_places': self.decimal_places,
- 'form_class': forms.DecimalField,
- **kwargs,
- })
+ return super().formfield(
+ **{
+ "max_digits": self.max_digits,
+ "decimal_places": self.decimal_places,
+ "form_class": forms.DecimalField,
+ **kwargs,
+ }
+ )
class DurationField(Field):
@@ -1584,10 +1721,13 @@ class DurationField(Field):
Use interval on PostgreSQL, INTERVAL DAY TO SECOND on Oracle, and bigint
of microseconds on other databases.
"""
+
empty_strings_allowed = False
default_error_messages = {
- 'invalid': _('“%(value)s” value has an invalid format. It must be in '
- '[DD] [[HH:]MM:]ss[.uuuuuu] format.')
+ "invalid": _(
+ "“%(value)s” value has an invalid format. It must be in "
+ "[DD] [[HH:]MM:]ss[.uuuuuu] format."
+ )
}
description = _("Duration")
@@ -1608,9 +1748,9 @@ class DurationField(Field):
return parsed
raise exceptions.ValidationError(
- self.error_messages['invalid'],
- code='invalid',
- params={'value': value},
+ self.error_messages["invalid"],
+ code="invalid",
+ params={"value": value},
)
def get_db_prep_value(self, value, connection, prepared=False):
@@ -1628,13 +1768,15 @@ class DurationField(Field):
def value_to_string(self, obj):
val = self.value_from_object(obj)
- return '' if val is None else duration_string(val)
+ return "" if val is None else duration_string(val)
def formfield(self, **kwargs):
- return super().formfield(**{
- 'form_class': forms.DurationField,
- **kwargs,
- })
+ return super().formfield(
+ **{
+ "form_class": forms.DurationField,
+ **kwargs,
+ }
+ )
class EmailField(CharField):
@@ -1643,7 +1785,7 @@ class EmailField(CharField):
def __init__(self, *args, **kwargs):
# max_length=254 to be compliant with RFCs 3696 and 5321
- kwargs.setdefault('max_length', 254)
+ kwargs.setdefault("max_length", 254)
super().__init__(*args, **kwargs)
def deconstruct(self):
@@ -1655,20 +1797,31 @@ class EmailField(CharField):
def formfield(self, **kwargs):
# As with CharField, this will cause email validation to be performed
# twice.
- return super().formfield(**{
- 'form_class': forms.EmailField,
- **kwargs,
- })
+ return super().formfield(
+ **{
+ "form_class": forms.EmailField,
+ **kwargs,
+ }
+ )
class FilePathField(Field):
description = _("File path")
- def __init__(self, verbose_name=None, name=None, path='', match=None,
- recursive=False, allow_files=True, allow_folders=False, **kwargs):
+ def __init__(
+ self,
+ verbose_name=None,
+ name=None,
+ path="",
+ match=None,
+ recursive=False,
+ allow_files=True,
+ allow_folders=False,
+ **kwargs,
+ ):
self.path, self.match, self.recursive = path, match, recursive
self.allow_files, self.allow_folders = allow_files, allow_folders
- kwargs.setdefault('max_length', 100)
+ kwargs.setdefault("max_length", 100)
super().__init__(verbose_name, name, **kwargs)
def check(self, **kwargs):
@@ -1683,23 +1836,23 @@ class FilePathField(Field):
checks.Error(
"FilePathFields must have either 'allow_files' or 'allow_folders' set to True.",
obj=self,
- id='fields.E140',
+ id="fields.E140",
)
]
return []
def deconstruct(self):
name, path, args, kwargs = super().deconstruct()
- if self.path != '':
- kwargs['path'] = self.path
+ if self.path != "":
+ kwargs["path"] = self.path
if self.match is not None:
- kwargs['match'] = self.match
+ kwargs["match"] = self.match
if self.recursive is not False:
- kwargs['recursive'] = self.recursive
+ kwargs["recursive"] = self.recursive
if self.allow_files is not True:
- kwargs['allow_files'] = self.allow_files
+ kwargs["allow_files"] = self.allow_files
if self.allow_folders is not False:
- kwargs['allow_folders'] = self.allow_folders
+ kwargs["allow_folders"] = self.allow_folders
if kwargs.get("max_length") == 100:
del kwargs["max_length"]
return name, path, args, kwargs
@@ -1711,15 +1864,17 @@ class FilePathField(Field):
return str(value)
def formfield(self, **kwargs):
- return super().formfield(**{
- 'path': self.path() if callable(self.path) else self.path,
- 'match': self.match,
- 'recursive': self.recursive,
- 'form_class': forms.FilePathField,
- 'allow_files': self.allow_files,
- 'allow_folders': self.allow_folders,
- **kwargs,
- })
+ return super().formfield(
+ **{
+ "path": self.path() if callable(self.path) else self.path,
+ "match": self.match,
+ "recursive": self.recursive,
+ "form_class": forms.FilePathField,
+ "allow_files": self.allow_files,
+ "allow_folders": self.allow_folders,
+ **kwargs,
+ }
+ )
def get_internal_type(self):
return "FilePathField"
@@ -1728,7 +1883,7 @@ class FilePathField(Field):
class FloatField(Field):
empty_strings_allowed = False
default_error_messages = {
- 'invalid': _('“%(value)s” value must be a float.'),
+ "invalid": _("“%(value)s” value must be a float."),
}
description = _("Floating point number")
@@ -1753,22 +1908,24 @@ class FloatField(Field):
return float(value)
except (TypeError, ValueError):
raise exceptions.ValidationError(
- self.error_messages['invalid'],
- code='invalid',
- params={'value': value},
+ self.error_messages["invalid"],
+ code="invalid",
+ params={"value": value},
)
def formfield(self, **kwargs):
- return super().formfield(**{
- 'form_class': forms.FloatField,
- **kwargs,
- })
+ return super().formfield(
+ **{
+ "form_class": forms.FloatField,
+ **kwargs,
+ }
+ )
class IntegerField(Field):
empty_strings_allowed = False
default_error_messages = {
- 'invalid': _('“%(value)s” value must be an integer.'),
+ "invalid": _("“%(value)s” value must be an integer."),
}
description = _("Integer")
@@ -1782,10 +1939,11 @@ class IntegerField(Field):
if self.max_length is not None:
return [
checks.Warning(
- "'max_length' is ignored when used with %s." % self.__class__.__name__,
+ "'max_length' is ignored when used with %s."
+ % self.__class__.__name__,
hint="Remove 'max_length' from field",
obj=self,
- id='fields.W122',
+ id="fields.W122",
)
]
return []
@@ -1799,22 +1957,28 @@ class IntegerField(Field):
min_value, max_value = connection.ops.integer_field_range(internal_type)
if min_value is not None and not any(
(
- isinstance(validator, validators.MinValueValidator) and (
+ isinstance(validator, validators.MinValueValidator)
+ and (
validator.limit_value()
if callable(validator.limit_value)
else validator.limit_value
- ) >= min_value
- ) for validator in validators_
+ )
+ >= min_value
+ )
+ for validator in validators_
):
validators_.append(validators.MinValueValidator(min_value))
if max_value is not None and not any(
(
- isinstance(validator, validators.MaxValueValidator) and (
+ isinstance(validator, validators.MaxValueValidator)
+ and (
validator.limit_value()
if callable(validator.limit_value)
else validator.limit_value
- ) <= max_value
- ) for validator in validators_
+ )
+ <= max_value
+ )
+ for validator in validators_
):
validators_.append(validators.MaxValueValidator(max_value))
return validators_
@@ -1840,16 +2004,18 @@ class IntegerField(Field):
return int(value)
except (TypeError, ValueError):
raise exceptions.ValidationError(
- self.error_messages['invalid'],
- code='invalid',
- params={'value': value},
+ self.error_messages["invalid"],
+ code="invalid",
+ params={"value": value},
)
def formfield(self, **kwargs):
- return super().formfield(**{
- 'form_class': forms.IntegerField,
- **kwargs,
- })
+ return super().formfield(
+ **{
+ "form_class": forms.IntegerField,
+ **kwargs,
+ }
+ )
class BigIntegerField(IntegerField):
@@ -1860,39 +2026,41 @@ class BigIntegerField(IntegerField):
return "BigIntegerField"
def formfield(self, **kwargs):
- return super().formfield(**{
- 'min_value': -BigIntegerField.MAX_BIGINT - 1,
- 'max_value': BigIntegerField.MAX_BIGINT,
- **kwargs,
- })
+ return super().formfield(
+ **{
+ "min_value": -BigIntegerField.MAX_BIGINT - 1,
+ "max_value": BigIntegerField.MAX_BIGINT,
+ **kwargs,
+ }
+ )
class SmallIntegerField(IntegerField):
- description = _('Small integer')
+ description = _("Small integer")
def get_internal_type(self):
- return 'SmallIntegerField'
+ return "SmallIntegerField"
class IPAddressField(Field):
empty_strings_allowed = False
description = _("IPv4 address")
system_check_removed_details = {
- 'msg': (
- 'IPAddressField has been removed except for support in '
- 'historical migrations.'
+ "msg": (
+ "IPAddressField has been removed except for support in "
+ "historical migrations."
),
- 'hint': 'Use GenericIPAddressField instead.',
- 'id': 'fields.E900',
+ "hint": "Use GenericIPAddressField instead.",
+ "id": "fields.E900",
}
def __init__(self, *args, **kwargs):
- kwargs['max_length'] = 15
+ kwargs["max_length"] = 15
super().__init__(*args, **kwargs)
def deconstruct(self):
name, path, args, kwargs = super().deconstruct()
- del kwargs['max_length']
+ del kwargs["max_length"]
return name, path, args, kwargs
def get_prep_value(self, value):
@@ -1910,14 +2078,23 @@ class GenericIPAddressField(Field):
description = _("IP address")
default_error_messages = {}
- def __init__(self, verbose_name=None, name=None, protocol='both',
- unpack_ipv4=False, *args, **kwargs):
+ def __init__(
+ self,
+ verbose_name=None,
+ name=None,
+ protocol="both",
+ unpack_ipv4=False,
+ *args,
+ **kwargs,
+ ):
self.unpack_ipv4 = unpack_ipv4
self.protocol = protocol
- self.default_validators, invalid_error_message = \
- validators.ip_address_validators(protocol, unpack_ipv4)
- self.default_error_messages['invalid'] = invalid_error_message
- kwargs['max_length'] = 39
+ (
+ self.default_validators,
+ invalid_error_message,
+ ) = validators.ip_address_validators(protocol, unpack_ipv4)
+ self.default_error_messages["invalid"] = invalid_error_message
+ kwargs["max_length"] = 39
super().__init__(verbose_name, name, *args, **kwargs)
def check(self, **kwargs):
@@ -1927,13 +2104,13 @@ class GenericIPAddressField(Field):
]
def _check_blank_and_null_values(self, **kwargs):
- if not getattr(self, 'null', False) and getattr(self, 'blank', False):
+ if not getattr(self, "null", False) and getattr(self, "blank", False):
return [
checks.Error(
- 'GenericIPAddressFields cannot have blank=True if null=False, '
- 'as blank values are stored as nulls.',
+ "GenericIPAddressFields cannot have blank=True if null=False, "
+ "as blank values are stored as nulls.",
obj=self,
- id='fields.E150',
+ id="fields.E150",
)
]
return []
@@ -1941,11 +2118,11 @@ class GenericIPAddressField(Field):
def deconstruct(self):
name, path, args, kwargs = super().deconstruct()
if self.unpack_ipv4 is not False:
- kwargs['unpack_ipv4'] = self.unpack_ipv4
+ kwargs["unpack_ipv4"] = self.unpack_ipv4
if self.protocol != "both":
- kwargs['protocol'] = self.protocol
+ kwargs["protocol"] = self.protocol
if kwargs.get("max_length") == 39:
- del kwargs['max_length']
+ del kwargs["max_length"]
return name, path, args, kwargs
def get_internal_type(self):
@@ -1957,8 +2134,10 @@ class GenericIPAddressField(Field):
if not isinstance(value, str):
value = str(value)
value = value.strip()
- if ':' in value:
- return clean_ipv6_address(value, self.unpack_ipv4, self.error_messages['invalid'])
+ if ":" in value:
+ return clean_ipv6_address(
+ value, self.unpack_ipv4, self.error_messages["invalid"]
+ )
return value
def get_db_prep_value(self, value, connection, prepared=False):
@@ -1970,7 +2149,7 @@ class GenericIPAddressField(Field):
value = super().get_prep_value(value)
if value is None:
return None
- if value and ':' in value:
+ if value and ":" in value:
try:
return clean_ipv6_address(value, self.unpack_ipv4)
except exceptions.ValidationError:
@@ -1978,44 +2157,46 @@ class GenericIPAddressField(Field):
return str(value)
def formfield(self, **kwargs):
- return super().formfield(**{
- 'protocol': self.protocol,
- 'form_class': forms.GenericIPAddressField,
- **kwargs,
- })
+ return super().formfield(
+ **{
+ "protocol": self.protocol,
+ "form_class": forms.GenericIPAddressField,
+ **kwargs,
+ }
+ )
class NullBooleanField(BooleanField):
default_error_messages = {
- 'invalid': _('“%(value)s” value must be either None, True or False.'),
- 'invalid_nullable': _('“%(value)s” value must be either None, True or False.'),
+ "invalid": _("“%(value)s” value must be either None, True or False."),
+ "invalid_nullable": _("“%(value)s” value must be either None, True or False."),
}
description = _("Boolean (Either True, False or None)")
system_check_removed_details = {
- 'msg': (
- 'NullBooleanField is removed except for support in historical '
- 'migrations.'
+ "msg": (
+ "NullBooleanField is removed except for support in historical "
+ "migrations."
),
- 'hint': 'Use BooleanField(null=True) instead.',
- 'id': 'fields.E903',
+ "hint": "Use BooleanField(null=True) instead.",
+ "id": "fields.E903",
}
def __init__(self, *args, **kwargs):
- kwargs['null'] = True
- kwargs['blank'] = True
+ kwargs["null"] = True
+ kwargs["blank"] = True
super().__init__(*args, **kwargs)
def deconstruct(self):
name, path, args, kwargs = super().deconstruct()
- del kwargs['null']
- del kwargs['blank']
+ del kwargs["null"]
+ del kwargs["blank"]
return name, path, args, kwargs
class PositiveIntegerRelDbTypeMixin:
def __init_subclass__(cls, **kwargs):
super().__init_subclass__(**kwargs)
- if not hasattr(cls, 'integer_field_class'):
+ if not hasattr(cls, "integer_field_class"):
cls.integer_field_class = next(
(
parent
@@ -2041,16 +2222,18 @@ class PositiveIntegerRelDbTypeMixin:
class PositiveBigIntegerField(PositiveIntegerRelDbTypeMixin, BigIntegerField):
- description = _('Positive big integer')
+ description = _("Positive big integer")
def get_internal_type(self):
- return 'PositiveBigIntegerField'
+ return "PositiveBigIntegerField"
def formfield(self, **kwargs):
- return super().formfield(**{
- 'min_value': 0,
- **kwargs,
- })
+ return super().formfield(
+ **{
+ "min_value": 0,
+ **kwargs,
+ }
+ )
class PositiveIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField):
@@ -2060,10 +2243,12 @@ class PositiveIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField):
return "PositiveIntegerField"
def formfield(self, **kwargs):
- return super().formfield(**{
- 'min_value': 0,
- **kwargs,
- })
+ return super().formfield(
+ **{
+ "min_value": 0,
+ **kwargs,
+ }
+ )
class PositiveSmallIntegerField(PositiveIntegerRelDbTypeMixin, SmallIntegerField):
@@ -2073,17 +2258,21 @@ class PositiveSmallIntegerField(PositiveIntegerRelDbTypeMixin, SmallIntegerField
return "PositiveSmallIntegerField"
def formfield(self, **kwargs):
- return super().formfield(**{
- 'min_value': 0,
- **kwargs,
- })
+ return super().formfield(
+ **{
+ "min_value": 0,
+ **kwargs,
+ }
+ )
class SlugField(CharField):
default_validators = [validators.validate_slug]
description = _("Slug (up to %(max_length)s)")
- def __init__(self, *args, max_length=50, db_index=True, allow_unicode=False, **kwargs):
+ def __init__(
+ self, *args, max_length=50, db_index=True, allow_unicode=False, **kwargs
+ ):
self.allow_unicode = allow_unicode
if self.allow_unicode:
self.default_validators = [validators.validate_unicode_slug]
@@ -2092,24 +2281,26 @@ class SlugField(CharField):
def deconstruct(self):
name, path, args, kwargs = super().deconstruct()
if kwargs.get("max_length") == 50:
- del kwargs['max_length']
+ del kwargs["max_length"]
if self.db_index is False:
- kwargs['db_index'] = False
+ kwargs["db_index"] = False
else:
- del kwargs['db_index']
+ del kwargs["db_index"]
if self.allow_unicode is not False:
- kwargs['allow_unicode'] = self.allow_unicode
+ kwargs["allow_unicode"] = self.allow_unicode
return name, path, args, kwargs
def get_internal_type(self):
return "SlugField"
def formfield(self, **kwargs):
- return super().formfield(**{
- 'form_class': forms.SlugField,
- 'allow_unicode': self.allow_unicode,
- **kwargs,
- })
+ return super().formfield(
+ **{
+ "form_class": forms.SlugField,
+ "allow_unicode": self.allow_unicode,
+ **kwargs,
+ }
+ )
class TextField(Field):
@@ -2120,7 +2311,7 @@ class TextField(Field):
self.db_collation = db_collation
def check(self, **kwargs):
- databases = kwargs.get('databases') or []
+ databases = kwargs.get("databases") or []
return [
*super().check(**kwargs),
*self._check_db_collation(databases),
@@ -2133,16 +2324,17 @@ class TextField(Field):
continue
connection = connections[db]
if not (
- self.db_collation is None or
- 'supports_collation_on_textfield' in self.model._meta.required_db_features or
- connection.features.supports_collation_on_textfield
+ self.db_collation is None
+ or "supports_collation_on_textfield"
+ in self.model._meta.required_db_features
+ or connection.features.supports_collation_on_textfield
):
errors.append(
checks.Error(
- '%s does not support a database collation on '
- 'TextFields.' % connection.display_name,
+ "%s does not support a database collation on "
+ "TextFields." % connection.display_name,
obj=self,
- id='fields.E190',
+ id="fields.E190",
),
)
return errors
@@ -2163,35 +2355,42 @@ class TextField(Field):
# Passing max_length to forms.CharField means that the value's length
# will be validated twice. This is considered acceptable since we want
# the value in the form field (to pass into widget for example).
- return super().formfield(**{
- 'max_length': self.max_length,
- **({} if self.choices is not None else {'widget': forms.Textarea}),
- **kwargs,
- })
+ return super().formfield(
+ **{
+ "max_length": self.max_length,
+ **({} if self.choices is not None else {"widget": forms.Textarea}),
+ **kwargs,
+ }
+ )
def deconstruct(self):
name, path, args, kwargs = super().deconstruct()
if self.db_collation:
- kwargs['db_collation'] = self.db_collation
+ kwargs["db_collation"] = self.db_collation
return name, path, args, kwargs
class TimeField(DateTimeCheckMixin, Field):
empty_strings_allowed = False
default_error_messages = {
- 'invalid': _('“%(value)s” value has an invalid format. It must be in '
- 'HH:MM[:ss[.uuuuuu]] format.'),
- 'invalid_time': _('“%(value)s” value has the correct format '
- '(HH:MM[:ss[.uuuuuu]]) but it is an invalid time.'),
+ "invalid": _(
+ "“%(value)s” value has an invalid format. It must be in "
+ "HH:MM[:ss[.uuuuuu]] format."
+ ),
+ "invalid_time": _(
+ "“%(value)s” value has the correct format "
+ "(HH:MM[:ss[.uuuuuu]]) but it is an invalid time."
+ ),
}
description = _("Time")
- def __init__(self, verbose_name=None, name=None, auto_now=False,
- auto_now_add=False, **kwargs):
+ def __init__(
+ self, verbose_name=None, name=None, auto_now=False, auto_now_add=False, **kwargs
+ ):
self.auto_now, self.auto_now_add = auto_now, auto_now_add
if auto_now or auto_now_add:
- kwargs['editable'] = False
- kwargs['blank'] = True
+ kwargs["editable"] = False
+ kwargs["blank"] = True
super().__init__(verbose_name, name, **kwargs)
def _check_fix_default_value(self):
@@ -2223,8 +2422,8 @@ class TimeField(DateTimeCheckMixin, Field):
if self.auto_now_add is not False:
kwargs["auto_now_add"] = self.auto_now_add
if self.auto_now or self.auto_now_add:
- del kwargs['blank']
- del kwargs['editable']
+ del kwargs["blank"]
+ del kwargs["editable"]
return name, path, args, kwargs
def get_internal_type(self):
@@ -2247,15 +2446,15 @@ class TimeField(DateTimeCheckMixin, Field):
return parsed
except ValueError:
raise exceptions.ValidationError(
- self.error_messages['invalid_time'],
- code='invalid_time',
- params={'value': value},
+ self.error_messages["invalid_time"],
+ code="invalid_time",
+ params={"value": value},
)
raise exceptions.ValidationError(
- self.error_messages['invalid'],
- code='invalid',
- params={'value': value},
+ self.error_messages["invalid"],
+ code="invalid",
+ params={"value": value},
)
def pre_save(self, model_instance, add):
@@ -2278,13 +2477,15 @@ class TimeField(DateTimeCheckMixin, Field):
def value_to_string(self, obj):
val = self.value_from_object(obj)
- return '' if val is None else val.isoformat()
+ return "" if val is None else val.isoformat()
def formfield(self, **kwargs):
- return super().formfield(**{
- 'form_class': forms.TimeField,
- **kwargs,
- })
+ return super().formfield(
+ **{
+ "form_class": forms.TimeField,
+ **kwargs,
+ }
+ )
class URLField(CharField):
@@ -2292,30 +2493,32 @@ class URLField(CharField):
description = _("URL")
def __init__(self, verbose_name=None, name=None, **kwargs):
- kwargs.setdefault('max_length', 200)
+ kwargs.setdefault("max_length", 200)
super().__init__(verbose_name, name, **kwargs)
def deconstruct(self):
name, path, args, kwargs = super().deconstruct()
if kwargs.get("max_length") == 200:
- del kwargs['max_length']
+ del kwargs["max_length"]
return name, path, args, kwargs
def formfield(self, **kwargs):
# As with CharField, this will cause URL validation to be performed
# twice.
- return super().formfield(**{
- 'form_class': forms.URLField,
- **kwargs,
- })
+ return super().formfield(
+ **{
+ "form_class": forms.URLField,
+ **kwargs,
+ }
+ )
class BinaryField(Field):
description = _("Raw binary data")
- empty_values = [None, b'']
+ empty_values = [None, b""]
def __init__(self, *args, **kwargs):
- kwargs.setdefault('editable', False)
+ kwargs.setdefault("editable", False)
super().__init__(*args, **kwargs)
if self.max_length is not None:
self.validators.append(validators.MaxLengthValidator(self.max_length))
@@ -2330,7 +2533,7 @@ class BinaryField(Field):
"BinaryField's default cannot be a string. Use bytes "
"content instead.",
obj=self,
- id='fields.E170',
+ id="fields.E170",
)
]
return []
@@ -2338,9 +2541,9 @@ class BinaryField(Field):
def deconstruct(self):
name, path, args, kwargs = super().deconstruct()
if self.editable:
- kwargs['editable'] = True
+ kwargs["editable"] = True
else:
- del kwargs['editable']
+ del kwargs["editable"]
return name, path, args, kwargs
def get_internal_type(self):
@@ -2353,8 +2556,8 @@ class BinaryField(Field):
if self.has_default() and not callable(self.default):
return self.default
default = super().get_default()
- if default == '':
- return b''
+ if default == "":
+ return b""
return default
def get_db_prep_value(self, value, connection, prepared=False):
@@ -2365,29 +2568,29 @@ class BinaryField(Field):
def value_to_string(self, obj):
"""Binary data is serialized as base64"""
- return b64encode(self.value_from_object(obj)).decode('ascii')
+ return b64encode(self.value_from_object(obj)).decode("ascii")
def to_python(self, value):
# If it's a string, it should be base64-encoded data
if isinstance(value, str):
- return memoryview(b64decode(value.encode('ascii')))
+ return memoryview(b64decode(value.encode("ascii")))
return value
class UUIDField(Field):
default_error_messages = {
- 'invalid': _('“%(value)s” is not a valid UUID.'),
+ "invalid": _("“%(value)s” is not a valid UUID."),
}
- description = _('Universally unique identifier')
+ description = _("Universally unique identifier")
empty_strings_allowed = False
def __init__(self, verbose_name=None, **kwargs):
- kwargs['max_length'] = 32
+ kwargs["max_length"] = 32
super().__init__(verbose_name, **kwargs)
def deconstruct(self):
name, path, args, kwargs = super().deconstruct()
- del kwargs['max_length']
+ del kwargs["max_length"]
return name, path, args, kwargs
def get_internal_type(self):
@@ -2409,29 +2612,31 @@ class UUIDField(Field):
def to_python(self, value):
if value is not None and not isinstance(value, uuid.UUID):
- input_form = 'int' if isinstance(value, int) else 'hex'
+ input_form = "int" if isinstance(value, int) else "hex"
try:
return uuid.UUID(**{input_form: value})
except (AttributeError, ValueError):
raise exceptions.ValidationError(
- self.error_messages['invalid'],
- code='invalid',
- params={'value': value},
+ self.error_messages["invalid"],
+ code="invalid",
+ params={"value": value},
)
return value
def formfield(self, **kwargs):
- return super().formfield(**{
- 'form_class': forms.UUIDField,
- **kwargs,
- })
+ return super().formfield(
+ **{
+ "form_class": forms.UUIDField,
+ **kwargs,
+ }
+ )
class AutoFieldMixin:
db_returning = True
def __init__(self, *args, **kwargs):
- kwargs['blank'] = True
+ kwargs["blank"] = True
super().__init__(*args, **kwargs)
def check(self, **kwargs):
@@ -2444,9 +2649,9 @@ class AutoFieldMixin:
if not self.primary_key:
return [
checks.Error(
- 'AutoFields must set primary_key=True.',
+ "AutoFields must set primary_key=True.",
obj=self,
- id='fields.E100',
+ id="fields.E100",
),
]
else:
@@ -2454,8 +2659,8 @@ class AutoFieldMixin:
def deconstruct(self):
name, path, args, kwargs = super().deconstruct()
- del kwargs['blank']
- kwargs['primary_key'] = True
+ del kwargs["blank"]
+ kwargs["primary_key"] = True
return name, path, args, kwargs
def validate(self, value, model_instance):
@@ -2502,34 +2707,35 @@ class AutoFieldMeta(type):
return (BigAutoField, SmallAutoField)
def __instancecheck__(self, instance):
- return isinstance(instance, self._subclasses) or super().__instancecheck__(instance)
+ return isinstance(instance, self._subclasses) or super().__instancecheck__(
+ instance
+ )
def __subclasscheck__(self, subclass):
- return issubclass(subclass, self._subclasses) or super().__subclasscheck__(subclass)
+ return issubclass(subclass, self._subclasses) or super().__subclasscheck__(
+ subclass
+ )
class AutoField(AutoFieldMixin, IntegerField, metaclass=AutoFieldMeta):
-
def get_internal_type(self):
- return 'AutoField'
+ return "AutoField"
def rel_db_type(self, connection):
return IntegerField().db_type(connection=connection)
class BigAutoField(AutoFieldMixin, BigIntegerField):
-
def get_internal_type(self):
- return 'BigAutoField'
+ return "BigAutoField"
def rel_db_type(self, connection):
return BigIntegerField().db_type(connection=connection)
class SmallAutoField(AutoFieldMixin, SmallIntegerField):
-
def get_internal_type(self):
- return 'SmallAutoField'
+ return "SmallAutoField"
def rel_db_type(self, connection):
return SmallIntegerField().db_type(connection=connection)