summaryrefslogtreecommitdiff
path: root/django/db/models/fields
diff options
context:
space:
mode:
authordjango-bot <ops@djangoproject.com>2022-02-03 20:24:19 +0100
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2022-02-07 20:37:05 +0100
commit9c19aff7c7561e3a82978a272ecdaad40dda5c00 (patch)
treef0506b668a013d0063e5fba3dbf4863b466713ba /django/db/models/fields
parentf68fa8b45dfac545cfc4111d4e52804c86db68d3 (diff)
Refs #33476 -- Reformatted code with Black.
Diffstat (limited to 'django/db/models/fields')
-rw-r--r--django/db/models/fields/__init__.py1094
-rw-r--r--django/db/models/fields/files.py123
-rw-r--r--django/db/models/fields/json.py249
-rw-r--r--django/db/models/fields/mixins.py19
-rw-r--r--django/db/models/fields/proxy.py4
-rw-r--r--django/db/models/fields/related.py883
-rw-r--r--django/db/models/fields/related_descriptors.py425
-rw-r--r--django/db/models/fields/related_lookups.py81
-rw-r--r--django/db/models/fields/reverse_related.py97
9 files changed, 1845 insertions, 1130 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)
diff --git a/django/db/models/fields/files.py b/django/db/models/fields/files.py
index 18900f7b85..33a1176ed6 100644
--- a/django/db/models/fields/files.py
+++ b/django/db/models/fields/files.py
@@ -24,7 +24,7 @@ class FieldFile(File):
def __eq__(self, other):
# Older code may be expecting FileField values to be simple strings.
# By overriding the == operator, it can remain backwards compatibility.
- if hasattr(other, 'name'):
+ if hasattr(other, "name"):
return self.name == other.name
return self.name == other
@@ -37,12 +37,14 @@ class FieldFile(File):
def _require_file(self):
if not self:
- raise ValueError("The '%s' attribute has no file associated with it." % self.field.name)
+ raise ValueError(
+ "The '%s' attribute has no file associated with it." % self.field.name
+ )
def _get_file(self):
self._require_file()
- if getattr(self, '_file', None) is None:
- self._file = self.storage.open(self.name, 'rb')
+ if getattr(self, "_file", None) is None:
+ self._file = self.storage.open(self.name, "rb")
return self._file
def _set_file(self, file):
@@ -70,13 +72,14 @@ class FieldFile(File):
return self.file.size
return self.storage.size(self.name)
- def open(self, mode='rb'):
+ def open(self, mode="rb"):
self._require_file()
- if getattr(self, '_file', None) is None:
+ if getattr(self, "_file", None) is None:
self.file = self.storage.open(self.name, mode)
else:
self.file.open(mode)
return self
+
# open() doesn't alter the file's contents, but it does reset the pointer
open.alters_data = True
@@ -93,6 +96,7 @@ class FieldFile(File):
# Save the object because it has changed, unless save is False
if save:
self.instance.save()
+
save.alters_data = True
def delete(self, save=True):
@@ -100,7 +104,7 @@ class FieldFile(File):
return
# Only close the file if it's already open, which we know by the
# presence of self._file
- if hasattr(self, '_file'):
+ if hasattr(self, "_file"):
self.close()
del self.file
@@ -112,15 +116,16 @@ class FieldFile(File):
if save:
self.instance.save()
+
delete.alters_data = True
@property
def closed(self):
- file = getattr(self, '_file', None)
+ file = getattr(self, "_file", None)
return file is None or file.closed
def close(self):
- file = getattr(self, '_file', None)
+ file = getattr(self, "_file", None)
if file is not None:
file.close()
@@ -129,12 +134,12 @@ class FieldFile(File):
# the file's name. Everything else will be restored later, by
# FileDescriptor below.
return {
- 'name': self.name,
- 'closed': False,
- '_committed': True,
- '_file': None,
- 'instance': self.instance,
- 'field': self.field,
+ "name": self.name,
+ "closed": False,
+ "_committed": True,
+ "_file": None,
+ "instance": self.instance,
+ "field": self.field,
}
def __setstate__(self, state):
@@ -156,6 +161,7 @@ class FileDescriptor(DeferredAttribute):
>>> with open('/path/to/hello.world') as f:
... instance.file = File(f)
"""
+
def __get__(self, instance, cls=None):
if instance is None:
return self
@@ -198,7 +204,7 @@ class FileDescriptor(DeferredAttribute):
# Finally, because of the (some would say boneheaded) way pickle works,
# the underlying FieldFile might not actually itself have an associated
# file. So we need to reset the details of the FieldFile in those cases.
- elif isinstance(file, FieldFile) and not hasattr(file, 'field'):
+ elif isinstance(file, FieldFile) and not hasattr(file, "field"):
file.instance = instance
file.field = self.field
file.storage = self.field.storage
@@ -225,8 +231,10 @@ class FileField(Field):
description = _("File")
- def __init__(self, verbose_name=None, name=None, upload_to='', storage=None, **kwargs):
- self._primary_key_set_explicitly = 'primary_key' in kwargs
+ def __init__(
+ self, verbose_name=None, name=None, upload_to="", storage=None, **kwargs
+ ):
+ self._primary_key_set_explicitly = "primary_key" in kwargs
self.storage = storage or default_storage
if callable(self.storage):
@@ -236,11 +244,15 @@ class FileField(Field):
if not isinstance(self.storage, Storage):
raise TypeError(
"%s.storage must be a subclass/instance of %s.%s"
- % (self.__class__.__qualname__, Storage.__module__, Storage.__qualname__)
+ % (
+ self.__class__.__qualname__,
+ Storage.__module__,
+ Storage.__qualname__,
+ )
)
self.upload_to = upload_to
- kwargs.setdefault('max_length', 100)
+ kwargs.setdefault("max_length", 100)
super().__init__(verbose_name, name, **kwargs)
def check(self, **kwargs):
@@ -254,23 +266,24 @@ class FileField(Field):
if self._primary_key_set_explicitly:
return [
checks.Error(
- "'primary_key' is not a valid argument for a %s." % self.__class__.__name__,
+ "'primary_key' is not a valid argument for a %s."
+ % self.__class__.__name__,
obj=self,
- id='fields.E201',
+ id="fields.E201",
)
]
else:
return []
def _check_upload_to(self):
- if isinstance(self.upload_to, str) and self.upload_to.startswith('/'):
+ if isinstance(self.upload_to, str) and self.upload_to.startswith("/"):
return [
checks.Error(
"%s's 'upload_to' argument must be a relative path, not an "
"absolute path." % self.__class__.__name__,
obj=self,
- id='fields.E202',
- hint='Remove the leading slash.',
+ id="fields.E202",
+ hint="Remove the leading slash.",
)
]
else:
@@ -280,9 +293,9 @@ class FileField(Field):
name, path, args, kwargs = super().deconstruct()
if kwargs.get("max_length") == 100:
del kwargs["max_length"]
- kwargs['upload_to'] = self.upload_to
+ kwargs["upload_to"] = self.upload_to
if self.storage is not default_storage:
- kwargs['storage'] = getattr(self, '_storage_callable', self.storage)
+ kwargs["storage"] = getattr(self, "_storage_callable", self.storage)
return name, path, args, kwargs
def get_internal_type(self):
@@ -329,14 +342,16 @@ class FileField(Field):
if data is not None:
# This value will be converted to str and stored in the
# database, so leaving False as-is is not acceptable.
- setattr(instance, self.name, data or '')
+ setattr(instance, self.name, data or "")
def formfield(self, **kwargs):
- return super().formfield(**{
- 'form_class': forms.FileField,
- 'max_length': self.max_length,
- **kwargs,
- })
+ return super().formfield(
+ **{
+ "form_class": forms.FileField,
+ "max_length": self.max_length,
+ **kwargs,
+ }
+ )
class ImageFileDescriptor(FileDescriptor):
@@ -344,6 +359,7 @@ class ImageFileDescriptor(FileDescriptor):
Just like the FileDescriptor, but for ImageFields. The only difference is
assigning the width/height to the width_field/height_field, if appropriate.
"""
+
def __set__(self, instance, value):
previous_file = instance.__dict__.get(self.field.attname)
super().__set__(instance, value)
@@ -364,7 +380,7 @@ class ImageFileDescriptor(FileDescriptor):
class ImageFieldFile(ImageFile, FieldFile):
def delete(self, save=True):
# Clear the image dimensions cache
- if hasattr(self, '_dimensions_cache'):
+ if hasattr(self, "_dimensions_cache"):
del self._dimensions_cache
super().delete(save)
@@ -374,7 +390,14 @@ class ImageField(FileField):
descriptor_class = ImageFileDescriptor
description = _("Image")
- def __init__(self, verbose_name=None, name=None, width_field=None, height_field=None, **kwargs):
+ def __init__(
+ self,
+ verbose_name=None,
+ name=None,
+ width_field=None,
+ height_field=None,
+ **kwargs,
+ ):
self.width_field, self.height_field = width_field, height_field
super().__init__(verbose_name, name, **kwargs)
@@ -390,11 +413,13 @@ class ImageField(FileField):
except ImportError:
return [
checks.Error(
- 'Cannot use ImageField because Pillow is not installed.',
- hint=('Get Pillow at https://pypi.org/project/Pillow/ '
- 'or run command "python -m pip install Pillow".'),
+ "Cannot use ImageField because Pillow is not installed.",
+ hint=(
+ "Get Pillow at https://pypi.org/project/Pillow/ "
+ 'or run command "python -m pip install Pillow".'
+ ),
obj=self,
- id='fields.E210',
+ id="fields.E210",
)
]
else:
@@ -403,9 +428,9 @@ class ImageField(FileField):
def deconstruct(self):
name, path, args, kwargs = super().deconstruct()
if self.width_field:
- kwargs['width_field'] = self.width_field
+ kwargs["width_field"] = self.width_field
if self.height_field:
- kwargs['height_field'] = self.height_field
+ kwargs["height_field"] = self.height_field
return name, path, args, kwargs
def contribute_to_class(self, cls, name, **kwargs):
@@ -445,9 +470,9 @@ class ImageField(FileField):
if not file and not force:
return
- dimension_fields_filled = not(
- (self.width_field and not getattr(instance, self.width_field)) or
- (self.height_field and not getattr(instance, self.height_field))
+ dimension_fields_filled = not (
+ (self.width_field and not getattr(instance, self.width_field))
+ or (self.height_field and not getattr(instance, self.height_field))
)
# When both dimension fields have values, we are most likely loading
# data from the database or updating an image field that already had
@@ -475,7 +500,9 @@ class ImageField(FileField):
setattr(instance, self.height_field, height)
def formfield(self, **kwargs):
- return super().formfield(**{
- 'form_class': forms.ImageField,
- **kwargs,
- })
+ return super().formfield(
+ **{
+ "form_class": forms.ImageField,
+ **kwargs,
+ }
+ )
diff --git a/django/db/models/fields/json.py b/django/db/models/fields/json.py
index efb4e2f6ed..fdca700c9d 100644
--- a/django/db/models/fields/json.py
+++ b/django/db/models/fields/json.py
@@ -10,32 +10,36 @@ from django.utils.translation import gettext_lazy as _
from . import Field
from .mixins import CheckFieldDefaultMixin
-__all__ = ['JSONField']
+__all__ = ["JSONField"]
class JSONField(CheckFieldDefaultMixin, Field):
empty_strings_allowed = False
- description = _('A JSON object')
+ description = _("A JSON object")
default_error_messages = {
- 'invalid': _('Value must be valid JSON.'),
+ "invalid": _("Value must be valid JSON."),
}
- _default_hint = ('dict', '{}')
+ _default_hint = ("dict", "{}")
def __init__(
- self, verbose_name=None, name=None, encoder=None, decoder=None,
+ self,
+ verbose_name=None,
+ name=None,
+ encoder=None,
+ decoder=None,
**kwargs,
):
if encoder and not callable(encoder):
- raise ValueError('The encoder parameter must be a callable object.')
+ raise ValueError("The encoder parameter must be a callable object.")
if decoder and not callable(decoder):
- raise ValueError('The decoder parameter must be a callable object.')
+ raise ValueError("The decoder parameter must be a callable object.")
self.encoder = encoder
self.decoder = decoder
super().__init__(verbose_name, name, **kwargs)
def check(self, **kwargs):
errors = super().check(**kwargs)
- databases = kwargs.get('databases') or []
+ databases = kwargs.get("databases") or []
errors.extend(self._check_supported(databases))
return errors
@@ -46,20 +50,19 @@ class JSONField(CheckFieldDefaultMixin, Field):
continue
connection = connections[db]
if (
- self.model._meta.required_db_vendor and
- self.model._meta.required_db_vendor != connection.vendor
+ self.model._meta.required_db_vendor
+ and self.model._meta.required_db_vendor != connection.vendor
):
continue
if not (
- 'supports_json_field' in self.model._meta.required_db_features or
- connection.features.supports_json_field
+ "supports_json_field" in self.model._meta.required_db_features
+ or connection.features.supports_json_field
):
errors.append(
checks.Error(
- '%s does not support JSONFields.'
- % connection.display_name,
+ "%s does not support JSONFields." % connection.display_name,
obj=self.model,
- id='fields.E180',
+ id="fields.E180",
)
)
return errors
@@ -67,9 +70,9 @@ class JSONField(CheckFieldDefaultMixin, Field):
def deconstruct(self):
name, path, args, kwargs = super().deconstruct()
if self.encoder is not None:
- kwargs['encoder'] = self.encoder
+ kwargs["encoder"] = self.encoder
if self.decoder is not None:
- kwargs['decoder'] = self.decoder
+ kwargs["decoder"] = self.decoder
return name, path, args, kwargs
def from_db_value(self, value, expression, connection):
@@ -85,7 +88,7 @@ class JSONField(CheckFieldDefaultMixin, Field):
return value
def get_internal_type(self):
- return 'JSONField'
+ return "JSONField"
def get_prep_value(self, value):
if value is None:
@@ -104,64 +107,66 @@ class JSONField(CheckFieldDefaultMixin, Field):
json.dumps(value, cls=self.encoder)
except TypeError:
raise exceptions.ValidationError(
- self.error_messages['invalid'],
- code='invalid',
- params={'value': value},
+ self.error_messages["invalid"],
+ code="invalid",
+ params={"value": value},
)
def value_to_string(self, obj):
return self.value_from_object(obj)
def formfield(self, **kwargs):
- return super().formfield(**{
- 'form_class': forms.JSONField,
- 'encoder': self.encoder,
- 'decoder': self.decoder,
- **kwargs,
- })
+ return super().formfield(
+ **{
+ "form_class": forms.JSONField,
+ "encoder": self.encoder,
+ "decoder": self.decoder,
+ **kwargs,
+ }
+ )
def compile_json_path(key_transforms, include_root=True):
- path = ['$'] if include_root else []
+ path = ["$"] if include_root else []
for key_transform in key_transforms:
try:
num = int(key_transform)
except ValueError: # non-integer
- path.append('.')
+ path.append(".")
path.append(json.dumps(key_transform))
else:
- path.append('[%s]' % num)
- return ''.join(path)
+ path.append("[%s]" % num)
+ return "".join(path)
class DataContains(PostgresOperatorLookup):
- lookup_name = 'contains'
- postgres_operator = '@>'
+ lookup_name = "contains"
+ postgres_operator = "@>"
def as_sql(self, compiler, connection):
if not connection.features.supports_json_field_contains:
raise NotSupportedError(
- 'contains lookup is not supported on this database backend.'
+ "contains lookup is not supported on this database backend."
)
lhs, lhs_params = self.process_lhs(compiler, connection)
rhs, rhs_params = self.process_rhs(compiler, connection)
params = tuple(lhs_params) + tuple(rhs_params)
- return 'JSON_CONTAINS(%s, %s)' % (lhs, rhs), params
+ return "JSON_CONTAINS(%s, %s)" % (lhs, rhs), params
class ContainedBy(PostgresOperatorLookup):
- lookup_name = 'contained_by'
- postgres_operator = '<@'
+ lookup_name = "contained_by"
+ postgres_operator = "<@"
def as_sql(self, compiler, connection):
if not connection.features.supports_json_field_contains:
raise NotSupportedError(
- 'contained_by lookup is not supported on this database backend.'
+ "contained_by lookup is not supported on this database backend."
)
lhs, lhs_params = self.process_lhs(compiler, connection)
rhs, rhs_params = self.process_rhs(compiler, connection)
params = tuple(rhs_params) + tuple(lhs_params)
- return 'JSON_CONTAINS(%s, %s)' % (rhs, lhs), params
+ return "JSON_CONTAINS(%s, %s)" % (rhs, lhs), params
class HasKeyLookup(PostgresOperatorLookup):
@@ -170,11 +175,13 @@ class HasKeyLookup(PostgresOperatorLookup):
def as_sql(self, compiler, connection, template=None):
# Process JSON path from the left-hand side.
if isinstance(self.lhs, KeyTransform):
- lhs, lhs_params, lhs_key_transforms = self.lhs.preprocess_lhs(compiler, connection)
+ lhs, lhs_params, lhs_key_transforms = self.lhs.preprocess_lhs(
+ compiler, connection
+ )
lhs_json_path = compile_json_path(lhs_key_transforms)
else:
lhs, lhs_params = self.process_lhs(compiler, connection)
- lhs_json_path = '$'
+ lhs_json_path = "$"
sql = template % lhs
# Process JSON path from the right-hand side.
rhs = self.rhs
@@ -186,20 +193,27 @@ class HasKeyLookup(PostgresOperatorLookup):
*_, rhs_key_transforms = key.preprocess_lhs(compiler, connection)
else:
rhs_key_transforms = [key]
- rhs_params.append('%s%s' % (
- lhs_json_path,
- compile_json_path(rhs_key_transforms, include_root=False),
- ))
+ rhs_params.append(
+ "%s%s"
+ % (
+ lhs_json_path,
+ compile_json_path(rhs_key_transforms, include_root=False),
+ )
+ )
# Add condition for each key.
if self.logical_operator:
- sql = '(%s)' % self.logical_operator.join([sql] * len(rhs_params))
+ sql = "(%s)" % self.logical_operator.join([sql] * len(rhs_params))
return sql, tuple(lhs_params) + tuple(rhs_params)
def as_mysql(self, compiler, connection):
- return self.as_sql(compiler, connection, template="JSON_CONTAINS_PATH(%s, 'one', %%s)")
+ return self.as_sql(
+ compiler, connection, template="JSON_CONTAINS_PATH(%s, 'one', %%s)"
+ )
def as_oracle(self, compiler, connection):
- sql, params = self.as_sql(compiler, connection, template="JSON_EXISTS(%s, '%%s')")
+ sql, params = self.as_sql(
+ compiler, connection, template="JSON_EXISTS(%s, '%%s')"
+ )
# Add paths directly into SQL because path expressions cannot be passed
# as bind variables on Oracle.
return sql % tuple(params), []
@@ -213,28 +227,30 @@ class HasKeyLookup(PostgresOperatorLookup):
return super().as_postgresql(compiler, connection)
def as_sqlite(self, compiler, connection):
- return self.as_sql(compiler, connection, template='JSON_TYPE(%s, %%s) IS NOT NULL')
+ return self.as_sql(
+ compiler, connection, template="JSON_TYPE(%s, %%s) IS NOT NULL"
+ )
class HasKey(HasKeyLookup):
- lookup_name = 'has_key'
- postgres_operator = '?'
+ lookup_name = "has_key"
+ postgres_operator = "?"
prepare_rhs = False
class HasKeys(HasKeyLookup):
- lookup_name = 'has_keys'
- postgres_operator = '?&'
- logical_operator = ' AND '
+ lookup_name = "has_keys"
+ postgres_operator = "?&"
+ logical_operator = " AND "
def get_prep_lookup(self):
return [str(item) for item in self.rhs]
class HasAnyKeys(HasKeys):
- lookup_name = 'has_any_keys'
- postgres_operator = '?|'
- logical_operator = ' OR '
+ lookup_name = "has_any_keys"
+ postgres_operator = "?|"
+ logical_operator = " OR "
class CaseInsensitiveMixin:
@@ -244,16 +260,17 @@ class CaseInsensitiveMixin:
Because utf8mb4_bin is a binary collation, comparison of JSON values is
case-sensitive.
"""
+
def process_lhs(self, compiler, connection):
lhs, lhs_params = super().process_lhs(compiler, connection)
- if connection.vendor == 'mysql':
- return 'LOWER(%s)' % lhs, lhs_params
+ if connection.vendor == "mysql":
+ return "LOWER(%s)" % lhs, lhs_params
return lhs, lhs_params
def process_rhs(self, compiler, connection):
rhs, rhs_params = super().process_rhs(compiler, connection)
- if connection.vendor == 'mysql':
- return 'LOWER(%s)' % rhs, rhs_params
+ if connection.vendor == "mysql":
+ return "LOWER(%s)" % rhs, rhs_params
return rhs, rhs_params
@@ -263,9 +280,9 @@ class JSONExact(lookups.Exact):
def process_rhs(self, compiler, connection):
rhs, rhs_params = super().process_rhs(compiler, connection)
# Treat None lookup values as null.
- if rhs == '%s' and rhs_params == [None]:
- rhs_params = ['null']
- if connection.vendor == 'mysql':
+ if rhs == "%s" and rhs_params == [None]:
+ rhs_params = ["null"]
+ if connection.vendor == "mysql":
func = ["JSON_EXTRACT(%s, '$')"] * len(rhs_params)
rhs = rhs % tuple(func)
return rhs, rhs_params
@@ -285,8 +302,8 @@ JSONField.register_lookup(JSONIContains)
class KeyTransform(Transform):
- postgres_operator = '->'
- postgres_nested_operator = '#>'
+ postgres_operator = "->"
+ postgres_nested_operator = "#>"
def __init__(self, key_name, *args, **kwargs):
super().__init__(*args, **kwargs)
@@ -299,41 +316,41 @@ class KeyTransform(Transform):
key_transforms.insert(0, previous.key_name)
previous = previous.lhs
lhs, params = compiler.compile(previous)
- if connection.vendor == 'oracle':
+ if connection.vendor == "oracle":
# Escape string-formatting.
- key_transforms = [key.replace('%', '%%') for key in key_transforms]
+ key_transforms = [key.replace("%", "%%") for key in key_transforms]
return lhs, params, key_transforms
def as_mysql(self, compiler, connection):
lhs, params, key_transforms = self.preprocess_lhs(compiler, connection)
json_path = compile_json_path(key_transforms)
- return 'JSON_EXTRACT(%s, %%s)' % lhs, tuple(params) + (json_path,)
+ return "JSON_EXTRACT(%s, %%s)" % lhs, tuple(params) + (json_path,)
def as_oracle(self, compiler, connection):
lhs, params, key_transforms = self.preprocess_lhs(compiler, connection)
json_path = compile_json_path(key_transforms)
return (
- "COALESCE(JSON_QUERY(%s, '%s'), JSON_VALUE(%s, '%s'))" %
- ((lhs, json_path) * 2)
+ "COALESCE(JSON_QUERY(%s, '%s'), JSON_VALUE(%s, '%s'))"
+ % ((lhs, json_path) * 2)
), tuple(params) * 2
def as_postgresql(self, compiler, connection):
lhs, params, key_transforms = self.preprocess_lhs(compiler, connection)
if len(key_transforms) > 1:
- sql = '(%s %s %%s)' % (lhs, self.postgres_nested_operator)
+ sql = "(%s %s %%s)" % (lhs, self.postgres_nested_operator)
return sql, tuple(params) + (key_transforms,)
try:
lookup = int(self.key_name)
except ValueError:
lookup = self.key_name
- return '(%s %s %%s)' % (lhs, self.postgres_operator), tuple(params) + (lookup,)
+ return "(%s %s %%s)" % (lhs, self.postgres_operator), tuple(params) + (lookup,)
def as_sqlite(self, compiler, connection):
lhs, params, key_transforms = self.preprocess_lhs(compiler, connection)
json_path = compile_json_path(key_transforms)
- datatype_values = ','.join([
- repr(datatype) for datatype in connection.ops.jsonfield_datatype_values
- ])
+ datatype_values = ",".join(
+ [repr(datatype) for datatype in connection.ops.jsonfield_datatype_values]
+ )
return (
"(CASE WHEN JSON_TYPE(%s, %%s) IN (%s) "
"THEN JSON_TYPE(%s, %%s) ELSE JSON_EXTRACT(%s, %%s) END)"
@@ -341,8 +358,8 @@ class KeyTransform(Transform):
class KeyTextTransform(KeyTransform):
- postgres_operator = '->>'
- postgres_nested_operator = '#>>'
+ postgres_operator = "->>"
+ postgres_nested_operator = "#>>"
class KeyTransformTextLookupMixin:
@@ -352,14 +369,16 @@ class KeyTransformTextLookupMixin:
key values to text and performing the lookup on the resulting
representation.
"""
+
def __init__(self, key_transform, *args, **kwargs):
if not isinstance(key_transform, KeyTransform):
raise TypeError(
- 'Transform should be an instance of KeyTransform in order to '
- 'use this lookup.'
+ "Transform should be an instance of KeyTransform in order to "
+ "use this lookup."
)
key_text_transform = KeyTextTransform(
- key_transform.key_name, *key_transform.source_expressions,
+ key_transform.key_name,
+ *key_transform.source_expressions,
**key_transform.extra,
)
super().__init__(key_text_transform, *args, **kwargs)
@@ -376,12 +395,12 @@ class KeyTransformIsNull(lookups.IsNull):
return sql, params
# Column doesn't have a key or IS NULL.
lhs, lhs_params, _ = self.lhs.preprocess_lhs(compiler, connection)
- return '(NOT %s OR %s IS NULL)' % (sql, lhs), tuple(params) + tuple(lhs_params)
+ return "(NOT %s OR %s IS NULL)" % (sql, lhs), tuple(params) + tuple(lhs_params)
def as_sqlite(self, compiler, connection):
- template = 'JSON_TYPE(%s, %%s) IS NULL'
+ template = "JSON_TYPE(%s, %%s) IS NULL"
if not self.rhs:
- template = 'JSON_TYPE(%s, %%s) IS NOT NULL'
+ template = "JSON_TYPE(%s, %%s) IS NOT NULL"
return HasKey(self.lhs.lhs, self.lhs.key_name).as_sql(
compiler,
connection,
@@ -392,26 +411,29 @@ class KeyTransformIsNull(lookups.IsNull):
class KeyTransformIn(lookups.In):
def resolve_expression_parameter(self, compiler, connection, sql, param):
sql, params = super().resolve_expression_parameter(
- compiler, connection, sql, param,
+ compiler,
+ connection,
+ sql,
+ param,
)
if (
- not hasattr(param, 'as_sql') and
- not connection.features.has_native_json_field
+ not hasattr(param, "as_sql")
+ and not connection.features.has_native_json_field
):
- if connection.vendor == 'oracle':
+ if connection.vendor == "oracle":
value = json.loads(param)
sql = "%s(JSON_OBJECT('value' VALUE %%s FORMAT JSON), '$.value')"
if isinstance(value, (list, dict)):
- sql = sql % 'JSON_QUERY'
+ sql = sql % "JSON_QUERY"
else:
- sql = sql % 'JSON_VALUE'
- elif connection.vendor == 'mysql' or (
- connection.vendor == 'sqlite' and
- params[0] not in connection.ops.jsonfield_datatype_values
+ sql = sql % "JSON_VALUE"
+ elif connection.vendor == "mysql" or (
+ connection.vendor == "sqlite"
+ and params[0] not in connection.ops.jsonfield_datatype_values
):
sql = "JSON_EXTRACT(%s, '$')"
- if connection.vendor == 'mysql' and connection.mysql_is_mariadb:
- sql = 'JSON_UNQUOTE(%s)' % sql
+ if connection.vendor == "mysql" and connection.mysql_is_mariadb:
+ sql = "JSON_UNQUOTE(%s)" % sql
return sql, params
@@ -420,21 +442,21 @@ class KeyTransformExact(JSONExact):
if isinstance(self.rhs, KeyTransform):
return super(lookups.Exact, self).process_rhs(compiler, connection)
rhs, rhs_params = super().process_rhs(compiler, connection)
- if connection.vendor == 'oracle':
+ if connection.vendor == "oracle":
func = []
sql = "%s(JSON_OBJECT('value' VALUE %%s FORMAT JSON), '$.value')"
for value in rhs_params:
value = json.loads(value)
if isinstance(value, (list, dict)):
- func.append(sql % 'JSON_QUERY')
+ func.append(sql % "JSON_QUERY")
else:
- func.append(sql % 'JSON_VALUE')
+ func.append(sql % "JSON_VALUE")
rhs = rhs % tuple(func)
- elif connection.vendor == 'sqlite':
+ elif connection.vendor == "sqlite":
func = []
for value in rhs_params:
if value in connection.ops.jsonfield_datatype_values:
- func.append('%s')
+ func.append("%s")
else:
func.append("JSON_EXTRACT(%s, '$')")
rhs = rhs % tuple(func)
@@ -442,24 +464,28 @@ class KeyTransformExact(JSONExact):
def as_oracle(self, compiler, connection):
rhs, rhs_params = super().process_rhs(compiler, connection)
- if rhs_params == ['null']:
+ if rhs_params == ["null"]:
# Field has key and it's NULL.
has_key_expr = HasKey(self.lhs.lhs, self.lhs.key_name)
has_key_sql, has_key_params = has_key_expr.as_oracle(compiler, connection)
- is_null_expr = self.lhs.get_lookup('isnull')(self.lhs, True)
+ is_null_expr = self.lhs.get_lookup("isnull")(self.lhs, True)
is_null_sql, is_null_params = is_null_expr.as_sql(compiler, connection)
return (
- '%s AND %s' % (has_key_sql, is_null_sql),
+ "%s AND %s" % (has_key_sql, is_null_sql),
tuple(has_key_params) + tuple(is_null_params),
)
return super().as_sql(compiler, connection)
-class KeyTransformIExact(CaseInsensitiveMixin, KeyTransformTextLookupMixin, lookups.IExact):
+class KeyTransformIExact(
+ CaseInsensitiveMixin, KeyTransformTextLookupMixin, lookups.IExact
+):
pass
-class KeyTransformIContains(CaseInsensitiveMixin, KeyTransformTextLookupMixin, lookups.IContains):
+class KeyTransformIContains(
+ CaseInsensitiveMixin, KeyTransformTextLookupMixin, lookups.IContains
+):
pass
@@ -467,7 +493,9 @@ class KeyTransformStartsWith(KeyTransformTextLookupMixin, lookups.StartsWith):
pass
-class KeyTransformIStartsWith(CaseInsensitiveMixin, KeyTransformTextLookupMixin, lookups.IStartsWith):
+class KeyTransformIStartsWith(
+ CaseInsensitiveMixin, KeyTransformTextLookupMixin, lookups.IStartsWith
+):
pass
@@ -475,7 +503,9 @@ class KeyTransformEndsWith(KeyTransformTextLookupMixin, lookups.EndsWith):
pass
-class KeyTransformIEndsWith(CaseInsensitiveMixin, KeyTransformTextLookupMixin, lookups.IEndsWith):
+class KeyTransformIEndsWith(
+ CaseInsensitiveMixin, KeyTransformTextLookupMixin, lookups.IEndsWith
+):
pass
@@ -483,7 +513,9 @@ class KeyTransformRegex(KeyTransformTextLookupMixin, lookups.Regex):
pass
-class KeyTransformIRegex(CaseInsensitiveMixin, KeyTransformTextLookupMixin, lookups.IRegex):
+class KeyTransformIRegex(
+ CaseInsensitiveMixin, KeyTransformTextLookupMixin, lookups.IRegex
+):
pass
@@ -530,7 +562,6 @@ KeyTransform.register_lookup(KeyTransformGte)
class KeyTransformFactory:
-
def __init__(self, key_name):
self.key_name = key_name
diff --git a/django/db/models/fields/mixins.py b/django/db/models/fields/mixins.py
index 3afa8d9304..e7f282210e 100644
--- a/django/db/models/fields/mixins.py
+++ b/django/db/models/fields/mixins.py
@@ -29,22 +29,25 @@ class FieldCacheMixin:
class CheckFieldDefaultMixin:
- _default_hint = ('<valid default>', '<invalid default>')
+ _default_hint = ("<valid default>", "<invalid default>")
def _check_default(self):
- if self.has_default() and self.default is not None and not callable(self.default):
+ if (
+ self.has_default()
+ and self.default is not None
+ and not callable(self.default)
+ ):
return [
checks.Warning(
"%s default should be a callable instead of an instance "
- "so that it's not shared between all field instances." % (
- self.__class__.__name__,
- ),
+ "so that it's not shared between all field instances."
+ % (self.__class__.__name__,),
hint=(
- 'Use a callable instead, e.g., use `%s` instead of '
- '`%s`.' % self._default_hint
+ "Use a callable instead, e.g., use `%s` instead of "
+ "`%s`." % self._default_hint
),
obj=self,
- id='fields.E010',
+ id="fields.E010",
)
]
else:
diff --git a/django/db/models/fields/proxy.py b/django/db/models/fields/proxy.py
index 0ecf04a333..ac02e47a25 100644
--- a/django/db/models/fields/proxy.py
+++ b/django/db/models/fields/proxy.py
@@ -13,6 +13,6 @@ class OrderWrt(fields.IntegerField):
"""
def __init__(self, *args, **kwargs):
- kwargs['name'] = '_order'
- kwargs['editable'] = False
+ kwargs["name"] = "_order"
+ kwargs["editable"] = False
super().__init__(*args, **kwargs)
diff --git a/django/db/models/fields/related.py b/django/db/models/fields/related.py
index 11407ac902..1cf447c6d4 100644
--- a/django/db/models/fields/related.py
+++ b/django/db/models/fields/related.py
@@ -19,19 +19,25 @@ from django.utils.translation import gettext_lazy as _
from . import Field
from .mixins import FieldCacheMixin
from .related_descriptors import (
- ForeignKeyDeferredAttribute, ForwardManyToOneDescriptor,
- ForwardOneToOneDescriptor, ManyToManyDescriptor,
- ReverseManyToOneDescriptor, ReverseOneToOneDescriptor,
+ ForeignKeyDeferredAttribute,
+ ForwardManyToOneDescriptor,
+ ForwardOneToOneDescriptor,
+ ManyToManyDescriptor,
+ ReverseManyToOneDescriptor,
+ ReverseOneToOneDescriptor,
)
from .related_lookups import (
- RelatedExact, RelatedGreaterThan, RelatedGreaterThanOrEqual, RelatedIn,
- RelatedIsNull, RelatedLessThan, RelatedLessThanOrEqual,
-)
-from .reverse_related import (
- ForeignObjectRel, ManyToManyRel, ManyToOneRel, OneToOneRel,
+ RelatedExact,
+ RelatedGreaterThan,
+ RelatedGreaterThanOrEqual,
+ RelatedIn,
+ RelatedIsNull,
+ RelatedLessThan,
+ RelatedLessThanOrEqual,
)
+from .reverse_related import ForeignObjectRel, ManyToManyRel, ManyToOneRel, OneToOneRel
-RECURSIVE_RELATIONSHIP_CONSTANT = 'self'
+RECURSIVE_RELATIONSHIP_CONSTANT = "self"
def resolve_relation(scope_model, relation):
@@ -119,19 +125,25 @@ class RelatedField(FieldCacheMixin, Field):
def _check_related_name_is_valid(self):
import keyword
+
related_name = self.remote_field.related_name
if related_name is None:
return []
- is_valid_id = not keyword.iskeyword(related_name) and related_name.isidentifier()
- if not (is_valid_id or related_name.endswith('+')):
+ is_valid_id = (
+ not keyword.iskeyword(related_name) and related_name.isidentifier()
+ )
+ if not (is_valid_id or related_name.endswith("+")):
return [
checks.Error(
- "The name '%s' is invalid related_name for field %s.%s" %
- (self.remote_field.related_name, self.model._meta.object_name,
- self.name),
+ "The name '%s' is invalid related_name for field %s.%s"
+ % (
+ self.remote_field.related_name,
+ self.model._meta.object_name,
+ self.name,
+ ),
hint="Related name must be a valid Python identifier or end with a '+'",
obj=self,
- id='fields.E306',
+ id="fields.E306",
)
]
return []
@@ -141,15 +153,17 @@ class RelatedField(FieldCacheMixin, Field):
return []
rel_query_name = self.related_query_name()
errors = []
- if rel_query_name.endswith('_'):
+ if rel_query_name.endswith("_"):
errors.append(
checks.Error(
"Reverse query name '%s' must not end with an underscore."
% rel_query_name,
- hint=("Add or change a related_name or related_query_name "
- "argument for this field."),
+ hint=(
+ "Add or change a related_name or related_query_name "
+ "argument for this field."
+ ),
obj=self,
- id='fields.E308',
+ id="fields.E308",
)
)
if LOOKUP_SEP in rel_query_name:
@@ -157,10 +171,12 @@ class RelatedField(FieldCacheMixin, Field):
checks.Error(
"Reverse query name '%s' must not contain '%s'."
% (rel_query_name, LOOKUP_SEP),
- hint=("Add or change a related_name or related_query_name "
- "argument for this field."),
+ hint=(
+ "Add or change a related_name or related_query_name "
+ "argument for this field."
+ ),
obj=self,
- id='fields.E309',
+ id="fields.E309",
)
)
return errors
@@ -168,29 +184,38 @@ class RelatedField(FieldCacheMixin, Field):
def _check_relation_model_exists(self):
rel_is_missing = self.remote_field.model not in self.opts.apps.get_models()
rel_is_string = isinstance(self.remote_field.model, str)
- model_name = self.remote_field.model if rel_is_string else self.remote_field.model._meta.object_name
- if rel_is_missing and (rel_is_string or not self.remote_field.model._meta.swapped):
+ model_name = (
+ self.remote_field.model
+ if rel_is_string
+ else self.remote_field.model._meta.object_name
+ )
+ if rel_is_missing and (
+ rel_is_string or not self.remote_field.model._meta.swapped
+ ):
return [
checks.Error(
"Field defines a relation with model '%s', which is either "
"not installed, or is abstract." % model_name,
obj=self,
- id='fields.E300',
+ id="fields.E300",
)
]
return []
def _check_referencing_to_swapped_model(self):
- if (self.remote_field.model not in self.opts.apps.get_models() and
- not isinstance(self.remote_field.model, str) and
- self.remote_field.model._meta.swapped):
+ if (
+ self.remote_field.model not in self.opts.apps.get_models()
+ and not isinstance(self.remote_field.model, str)
+ and self.remote_field.model._meta.swapped
+ ):
return [
checks.Error(
"Field defines a relation with the model '%s', which has "
"been swapped out." % self.remote_field.model._meta.label,
- hint="Update the relation to point at 'settings.%s'." % self.remote_field.model._meta.swappable,
+ hint="Update the relation to point at 'settings.%s'."
+ % self.remote_field.model._meta.swappable,
obj=self,
- id='fields.E301',
+ id="fields.E301",
)
]
return []
@@ -227,7 +252,7 @@ class RelatedField(FieldCacheMixin, Field):
rel_name = self.remote_field.get_accessor_name() # i. e. "model_set"
rel_query_name = self.related_query_name() # i. e. "model"
# i.e. "app_label.Model.field".
- field_name = '%s.%s' % (opts.label, self.name)
+ field_name = "%s.%s" % (opts.label, self.name)
# Check clashes between accessor or reverse query name of `field`
# and any other field name -- i.e. accessor for Model.foreign is
@@ -235,28 +260,35 @@ class RelatedField(FieldCacheMixin, Field):
potential_clashes = rel_opts.fields + rel_opts.many_to_many
for clash_field in potential_clashes:
# i.e. "app_label.Target.model_set".
- clash_name = '%s.%s' % (rel_opts.label, clash_field.name)
+ clash_name = "%s.%s" % (rel_opts.label, clash_field.name)
if not rel_is_hidden and clash_field.name == rel_name:
errors.append(
checks.Error(
f"Reverse accessor '{rel_opts.object_name}.{rel_name}' "
f"for '{field_name}' clashes with field name "
f"'{clash_name}'.",
- hint=("Rename field '%s', or add/change a related_name "
- "argument to the definition for field '%s'.") % (clash_name, field_name),
+ hint=(
+ "Rename field '%s', or add/change a related_name "
+ "argument to the definition for field '%s'."
+ )
+ % (clash_name, field_name),
obj=self,
- id='fields.E302',
+ id="fields.E302",
)
)
if clash_field.name == rel_query_name:
errors.append(
checks.Error(
- "Reverse query name for '%s' clashes with field name '%s'." % (field_name, clash_name),
- hint=("Rename field '%s', or add/change a related_name "
- "argument to the definition for field '%s'.") % (clash_name, field_name),
+ "Reverse query name for '%s' clashes with field name '%s'."
+ % (field_name, clash_name),
+ hint=(
+ "Rename field '%s', or add/change a related_name "
+ "argument to the definition for field '%s'."
+ )
+ % (clash_name, field_name),
obj=self,
- id='fields.E303',
+ id="fields.E303",
)
)
@@ -266,7 +298,7 @@ class RelatedField(FieldCacheMixin, Field):
potential_clashes = (r for r in rel_opts.related_objects if r.field is not self)
for clash_field in potential_clashes:
# i.e. "app_label.Model.m2m".
- clash_name = '%s.%s' % (
+ clash_name = "%s.%s" % (
clash_field.related_model._meta.label,
clash_field.field.name,
)
@@ -276,10 +308,13 @@ class RelatedField(FieldCacheMixin, Field):
f"Reverse accessor '{rel_opts.object_name}.{rel_name}' "
f"for '{field_name}' clashes with reverse accessor for "
f"'{clash_name}'.",
- hint=("Add or change a related_name argument "
- "to the definition for '%s' or '%s'.") % (field_name, clash_name),
+ hint=(
+ "Add or change a related_name argument "
+ "to the definition for '%s' or '%s'."
+ )
+ % (field_name, clash_name),
obj=self,
- id='fields.E304',
+ id="fields.E304",
)
)
@@ -288,10 +323,13 @@ class RelatedField(FieldCacheMixin, Field):
checks.Error(
"Reverse query name for '%s' clashes with reverse query name for '%s'."
% (field_name, clash_name),
- hint=("Add or change a related_name argument "
- "to the definition for '%s' or '%s'.") % (field_name, clash_name),
+ hint=(
+ "Add or change a related_name argument "
+ "to the definition for '%s' or '%s'."
+ )
+ % (field_name, clash_name),
obj=self,
- id='fields.E305',
+ id="fields.E305",
)
)
@@ -315,32 +353,35 @@ class RelatedField(FieldCacheMixin, Field):
related_name = self.opts.default_related_name
if related_name:
related_name = related_name % {
- 'class': cls.__name__.lower(),
- 'model_name': cls._meta.model_name.lower(),
- 'app_label': cls._meta.app_label.lower()
+ "class": cls.__name__.lower(),
+ "model_name": cls._meta.model_name.lower(),
+ "app_label": cls._meta.app_label.lower(),
}
self.remote_field.related_name = related_name
if self.remote_field.related_query_name:
related_query_name = self.remote_field.related_query_name % {
- 'class': cls.__name__.lower(),
- 'app_label': cls._meta.app_label.lower(),
+ "class": cls.__name__.lower(),
+ "app_label": cls._meta.app_label.lower(),
}
self.remote_field.related_query_name = related_query_name
def resolve_related_class(model, related, field):
field.remote_field.model = related
field.do_related_class(related, model)
- lazy_related_operation(resolve_related_class, cls, self.remote_field.model, field=self)
+
+ lazy_related_operation(
+ resolve_related_class, cls, self.remote_field.model, field=self
+ )
def deconstruct(self):
name, path, args, kwargs = super().deconstruct()
if self._limit_choices_to:
- kwargs['limit_choices_to'] = self._limit_choices_to
+ kwargs["limit_choices_to"] = self._limit_choices_to
if self._related_name is not None:
- kwargs['related_name'] = self._related_name
+ kwargs["related_name"] = self._related_name
if self._related_query_name is not None:
- kwargs['related_query_name'] = self._related_query_name
+ kwargs["related_query_name"] = self._related_query_name
return name, path, args, kwargs
def get_forward_related_filter(self, obj):
@@ -352,7 +393,7 @@ class RelatedField(FieldCacheMixin, Field):
self.related_field.model.
"""
return {
- '%s__%s' % (self.name, rh_field.name): getattr(obj, rh_field.attname)
+ "%s__%s" % (self.name, rh_field.name): getattr(obj, rh_field.attname)
for _, rh_field in self.related_fields
}
@@ -391,9 +432,10 @@ class RelatedField(FieldCacheMixin, Field):
return None
def set_attributes_from_rel(self):
- self.name = (
- self.name or
- (self.remote_field.model._meta.model_name + '_' + self.remote_field.model._meta.pk.name)
+ self.name = self.name or (
+ self.remote_field.model._meta.model_name
+ + "_"
+ + self.remote_field.model._meta.pk.name
)
if self.verbose_name is None:
self.verbose_name = self.remote_field.model._meta.verbose_name
@@ -423,14 +465,16 @@ class RelatedField(FieldCacheMixin, Field):
being constructed.
"""
defaults = {}
- if hasattr(self.remote_field, 'get_related_field'):
+ if hasattr(self.remote_field, "get_related_field"):
# If this is a callable, do not invoke it here. Just pass
# it in the defaults for when the form class will later be
# instantiated.
limit_choices_to = self.remote_field.limit_choices_to
- defaults.update({
- 'limit_choices_to': limit_choices_to,
- })
+ defaults.update(
+ {
+ "limit_choices_to": limit_choices_to,
+ }
+ )
defaults.update(kwargs)
return super().formfield(**defaults)
@@ -439,7 +483,11 @@ class RelatedField(FieldCacheMixin, Field):
Define the name that can be used to identify this related object in a
table-spanning query.
"""
- return self.remote_field.related_query_name or self.remote_field.related_name or self.opts.model_name
+ return (
+ self.remote_field.related_query_name
+ or self.remote_field.related_name
+ or self.opts.model_name
+ )
@property
def target_field(self):
@@ -450,7 +498,8 @@ class RelatedField(FieldCacheMixin, Field):
target_fields = self.path_infos[-1].target_fields
if len(target_fields) > 1:
raise exceptions.FieldError(
- "The relation has multiple target fields, but only single target field was asked for")
+ "The relation has multiple target fields, but only single target field was asked for"
+ )
return target_fields[0]
def get_cache_name(self):
@@ -473,13 +522,25 @@ class ForeignObject(RelatedField):
forward_related_accessor_class = ForwardManyToOneDescriptor
rel_class = ForeignObjectRel
- def __init__(self, to, on_delete, from_fields, to_fields, rel=None, related_name=None,
- related_query_name=None, limit_choices_to=None, parent_link=False,
- swappable=True, **kwargs):
+ def __init__(
+ self,
+ to,
+ on_delete,
+ from_fields,
+ to_fields,
+ rel=None,
+ related_name=None,
+ related_query_name=None,
+ limit_choices_to=None,
+ parent_link=False,
+ swappable=True,
+ **kwargs,
+ ):
if rel is None:
rel = self.rel_class(
- self, to,
+ self,
+ to,
related_name=related_name,
related_query_name=related_query_name,
limit_choices_to=limit_choices_to,
@@ -502,8 +563,8 @@ class ForeignObject(RelatedField):
def __copy__(self):
obj = super().__copy__()
# Remove any cached PathInfo values.
- obj.__dict__.pop('path_infos', None)
- obj.__dict__.pop('reverse_path_infos', None)
+ obj.__dict__.pop("path_infos", None)
+ obj.__dict__.pop("reverse_path_infos", None)
return obj
def check(self, **kwargs):
@@ -530,7 +591,7 @@ class ForeignObject(RelatedField):
"model '%s'."
% (to_field, self.remote_field.model._meta.label),
obj=self,
- id='fields.E312',
+ id="fields.E312",
)
)
return errors
@@ -551,21 +612,22 @@ class ForeignObject(RelatedField):
unique_foreign_fields = {
frozenset([f.name])
for f in self.remote_field.model._meta.get_fields()
- if getattr(f, 'unique', False)
+ if getattr(f, "unique", False)
}
- unique_foreign_fields.update({
- frozenset(ut)
- for ut in self.remote_field.model._meta.unique_together
- })
- unique_foreign_fields.update({
- frozenset(uc.fields)
- for uc in self.remote_field.model._meta.total_unique_constraints
- })
+ unique_foreign_fields.update(
+ {frozenset(ut) for ut in self.remote_field.model._meta.unique_together}
+ )
+ unique_foreign_fields.update(
+ {
+ frozenset(uc.fields)
+ for uc in self.remote_field.model._meta.total_unique_constraints
+ }
+ )
foreign_fields = {f.name for f in self.foreign_related_fields}
has_unique_constraint = any(u <= foreign_fields for u in unique_foreign_fields)
if not has_unique_constraint and len(self.foreign_related_fields) > 1:
- field_combination = ', '.join(
+ field_combination = ", ".join(
"'%s'" % rel_field.name for rel_field in self.foreign_related_fields
)
model_name = self.remote_field.model.__name__
@@ -574,13 +636,13 @@ class ForeignObject(RelatedField):
"No subset of the fields %s on model '%s' is unique."
% (field_combination, model_name),
hint=(
- 'Mark a single field as unique=True or add a set of '
- 'fields to a unique constraint (via unique_together '
- 'or a UniqueConstraint (without condition) in the '
- 'model Meta.constraints).'
+ "Mark a single field as unique=True or add a set of "
+ "fields to a unique constraint (via unique_together "
+ "or a UniqueConstraint (without condition) in the "
+ "model Meta.constraints)."
),
obj=self,
- id='fields.E310',
+ id="fields.E310",
)
]
elif not has_unique_constraint:
@@ -591,12 +653,12 @@ class ForeignObject(RelatedField):
"'%s.%s' must be unique because it is referenced by "
"a foreign key." % (model_name, field_name),
hint=(
- 'Add unique=True to this field or add a '
- 'UniqueConstraint (without condition) in the model '
- 'Meta.constraints.'
+ "Add unique=True to this field or add a "
+ "UniqueConstraint (without condition) in the model "
+ "Meta.constraints."
),
obj=self,
- id='fields.E311',
+ id="fields.E311",
)
]
else:
@@ -604,44 +666,48 @@ class ForeignObject(RelatedField):
def deconstruct(self):
name, path, args, kwargs = super().deconstruct()
- kwargs['on_delete'] = self.remote_field.on_delete
- kwargs['from_fields'] = self.from_fields
- kwargs['to_fields'] = self.to_fields
+ kwargs["on_delete"] = self.remote_field.on_delete
+ kwargs["from_fields"] = self.from_fields
+ kwargs["to_fields"] = self.to_fields
if self.remote_field.parent_link:
- kwargs['parent_link'] = self.remote_field.parent_link
+ kwargs["parent_link"] = self.remote_field.parent_link
if isinstance(self.remote_field.model, str):
- if '.' in self.remote_field.model:
- app_label, model_name = self.remote_field.model.split('.')
- kwargs['to'] = '%s.%s' % (app_label, model_name.lower())
+ if "." in self.remote_field.model:
+ app_label, model_name = self.remote_field.model.split(".")
+ kwargs["to"] = "%s.%s" % (app_label, model_name.lower())
else:
- kwargs['to'] = self.remote_field.model.lower()
+ kwargs["to"] = self.remote_field.model.lower()
else:
- kwargs['to'] = self.remote_field.model._meta.label_lower
+ kwargs["to"] = self.remote_field.model._meta.label_lower
# If swappable is True, then see if we're actually pointing to the target
# of a swap.
swappable_setting = self.swappable_setting
if swappable_setting is not None:
# If it's already a settings reference, error
- if hasattr(kwargs['to'], "setting_name"):
- if kwargs['to'].setting_name != swappable_setting:
+ if hasattr(kwargs["to"], "setting_name"):
+ if kwargs["to"].setting_name != swappable_setting:
raise ValueError(
"Cannot deconstruct a ForeignKey pointing to a model "
"that is swapped in place of more than one model (%s and %s)"
- % (kwargs['to'].setting_name, swappable_setting)
+ % (kwargs["to"].setting_name, swappable_setting)
)
# Set it
- kwargs['to'] = SettingsReference(
- kwargs['to'],
+ kwargs["to"] = SettingsReference(
+ kwargs["to"],
swappable_setting,
)
return name, path, args, kwargs
def resolve_related_fields(self):
if not self.from_fields or len(self.from_fields) != len(self.to_fields):
- raise ValueError('Foreign Object from and to fields must be the same non-zero length')
+ raise ValueError(
+ "Foreign Object from and to fields must be the same non-zero length"
+ )
if isinstance(self.remote_field.model, str):
- raise ValueError('Related model %r cannot be resolved' % self.remote_field.model)
+ raise ValueError(
+ "Related model %r cannot be resolved" % self.remote_field.model
+ )
related_fields = []
for index in range(len(self.from_fields)):
from_field_name = self.from_fields[index]
@@ -651,8 +717,11 @@ class ForeignObject(RelatedField):
if from_field_name == RECURSIVE_RELATIONSHIP_CONSTANT
else self.opts.get_field(from_field_name)
)
- to_field = (self.remote_field.model._meta.pk if to_field_name is None
- else self.remote_field.model._meta.get_field(to_field_name))
+ to_field = (
+ self.remote_field.model._meta.pk
+ if to_field_name is None
+ else self.remote_field.model._meta.get_field(to_field_name)
+ )
related_fields.append((from_field, to_field))
return related_fields
@@ -670,7 +739,9 @@ class ForeignObject(RelatedField):
@cached_property
def foreign_related_fields(self):
- return tuple(rhs_field for lhs_field, rhs_field in self.related_fields if rhs_field)
+ return tuple(
+ rhs_field for lhs_field, rhs_field in self.related_fields if rhs_field
+ )
def get_local_related_value(self, instance):
return self.get_instance_value_for_fields(instance, self.local_related_fields)
@@ -688,9 +759,11 @@ class ForeignObject(RelatedField):
# instance.pk (that is, parent_ptr_id) when asked for instance.id.
if field.primary_key:
possible_parent_link = opts.get_ancestor_link(field.model)
- if (not possible_parent_link or
- possible_parent_link.primary_key or
- possible_parent_link.model._meta.abstract):
+ if (
+ not possible_parent_link
+ or possible_parent_link.primary_key
+ or possible_parent_link.model._meta.abstract
+ ):
ret.append(instance.pk)
continue
ret.append(getattr(instance, field.attname))
@@ -702,7 +775,9 @@ class ForeignObject(RelatedField):
def get_joining_columns(self, reverse_join=False):
source = self.reverse_related_fields if reverse_join else self.related_fields
- return tuple((lhs_field.column, rhs_field.column) for lhs_field, rhs_field in source)
+ return tuple(
+ (lhs_field.column, rhs_field.column) for lhs_field, rhs_field in source
+ )
def get_reverse_joining_columns(self):
return self.get_joining_columns(reverse_join=True)
@@ -740,15 +815,17 @@ class ForeignObject(RelatedField):
"""Get path from this field to the related model."""
opts = self.remote_field.model._meta
from_opts = self.model._meta
- return [PathInfo(
- from_opts=from_opts,
- to_opts=opts,
- target_fields=self.foreign_related_fields,
- join_field=self,
- m2m=False,
- direct=True,
- filtered_relation=filtered_relation,
- )]
+ return [
+ PathInfo(
+ from_opts=from_opts,
+ to_opts=opts,
+ target_fields=self.foreign_related_fields,
+ join_field=self,
+ m2m=False,
+ direct=True,
+ filtered_relation=filtered_relation,
+ )
+ ]
@cached_property
def path_infos(self):
@@ -758,15 +835,17 @@ class ForeignObject(RelatedField):
"""Get path from the related model to this field's model."""
opts = self.model._meta
from_opts = self.remote_field.model._meta
- return [PathInfo(
- from_opts=from_opts,
- to_opts=opts,
- target_fields=(opts.pk,),
- join_field=self.remote_field,
- m2m=not self.unique,
- direct=False,
- filtered_relation=filtered_relation,
- )]
+ return [
+ PathInfo(
+ from_opts=from_opts,
+ to_opts=opts,
+ target_fields=(opts.pk,),
+ join_field=self.remote_field,
+ m2m=not self.unique,
+ direct=False,
+ filtered_relation=filtered_relation,
+ )
+ ]
@cached_property
def reverse_path_infos(self):
@@ -776,8 +855,8 @@ class ForeignObject(RelatedField):
@functools.lru_cache(maxsize=None)
def get_lookups(cls):
bases = inspect.getmro(cls)
- bases = bases[:bases.index(ForeignObject) + 1]
- class_lookups = [parent.__dict__.get('class_lookups', {}) for parent in bases]
+ bases = bases[: bases.index(ForeignObject) + 1]
+ class_lookups = [parent.__dict__.get("class_lookups", {}) for parent in bases]
return cls.merge_dicts(class_lookups)
def contribute_to_class(self, cls, name, private_only=False, **kwargs):
@@ -787,13 +866,22 @@ class ForeignObject(RelatedField):
def contribute_to_related_class(self, cls, related):
# Internal FK's - i.e., those with a related name ending with '+' -
# and swapped models don't get a related descriptor.
- if not self.remote_field.is_hidden() and not related.related_model._meta.swapped:
- setattr(cls._meta.concrete_model, related.get_accessor_name(), self.related_accessor_class(related))
+ if (
+ not self.remote_field.is_hidden()
+ and not related.related_model._meta.swapped
+ ):
+ setattr(
+ cls._meta.concrete_model,
+ related.get_accessor_name(),
+ self.related_accessor_class(related),
+ )
# While 'limit_choices_to' might be a callable, simply pass
# it along for later - this is too early because it's still
# model load time.
if self.remote_field.limit_choices_to:
- cls._meta.related_fkey_lookups.append(self.remote_field.limit_choices_to)
+ cls._meta.related_fkey_lookups.append(
+ self.remote_field.limit_choices_to
+ )
ForeignObject.register_lookup(RelatedIn)
@@ -813,6 +901,7 @@ class ForeignKey(ForeignObject):
By default ForeignKey will target the pk of the remote model but this
behavior can be changed by using the ``to_field`` argument.
"""
+
descriptor_class = ForeignKeyDeferredAttribute
# Field flags
many_to_many = False
@@ -824,21 +913,33 @@ class ForeignKey(ForeignObject):
empty_strings_allowed = False
default_error_messages = {
- 'invalid': _('%(model)s instance with %(field)s %(value)r does not exist.')
+ "invalid": _("%(model)s instance with %(field)s %(value)r does not exist.")
}
description = _("Foreign Key (type determined by related field)")
- def __init__(self, to, on_delete, related_name=None, related_query_name=None,
- limit_choices_to=None, parent_link=False, to_field=None,
- db_constraint=True, **kwargs):
+ def __init__(
+ self,
+ to,
+ on_delete,
+ related_name=None,
+ related_query_name=None,
+ limit_choices_to=None,
+ parent_link=False,
+ to_field=None,
+ db_constraint=True,
+ **kwargs,
+ ):
try:
to._meta.model_name
except AttributeError:
if not isinstance(to, str):
raise TypeError(
- '%s(%r) is invalid. First parameter to ForeignKey must be '
- 'either a model, a model name, or the string %r' % (
- self.__class__.__name__, to, RECURSIVE_RELATIONSHIP_CONSTANT,
+ "%s(%r) is invalid. First parameter to ForeignKey must be "
+ "either a model, a model name, or the string %r"
+ % (
+ self.__class__.__name__,
+ to,
+ RECURSIVE_RELATIONSHIP_CONSTANT,
)
)
else:
@@ -847,17 +948,19 @@ class ForeignKey(ForeignObject):
# be correct until contribute_to_class is called. Refs #12190.
to_field = to_field or (to._meta.pk and to._meta.pk.name)
if not callable(on_delete):
- raise TypeError('on_delete must be callable.')
+ raise TypeError("on_delete must be callable.")
- kwargs['rel'] = self.rel_class(
- self, to, to_field,
+ kwargs["rel"] = self.rel_class(
+ self,
+ to,
+ to_field,
related_name=related_name,
related_query_name=related_query_name,
limit_choices_to=limit_choices_to,
parent_link=parent_link,
on_delete=on_delete,
)
- kwargs.setdefault('db_index', True)
+ kwargs.setdefault("db_index", True)
super().__init__(
to,
@@ -879,54 +982,60 @@ class ForeignKey(ForeignObject):
]
def _check_on_delete(self):
- on_delete = getattr(self.remote_field, 'on_delete', None)
+ on_delete = getattr(self.remote_field, "on_delete", None)
if on_delete == SET_NULL and not self.null:
return [
checks.Error(
- 'Field specifies on_delete=SET_NULL, but cannot be null.',
- hint='Set null=True argument on the field, or change the on_delete rule.',
+ "Field specifies on_delete=SET_NULL, but cannot be null.",
+ hint="Set null=True argument on the field, or change the on_delete rule.",
obj=self,
- id='fields.E320',
+ id="fields.E320",
)
]
elif on_delete == SET_DEFAULT and not self.has_default():
return [
checks.Error(
- 'Field specifies on_delete=SET_DEFAULT, but has no default value.',
- hint='Set a default value, or change the on_delete rule.',
+ "Field specifies on_delete=SET_DEFAULT, but has no default value.",
+ hint="Set a default value, or change the on_delete rule.",
obj=self,
- id='fields.E321',
+ id="fields.E321",
)
]
else:
return []
def _check_unique(self, **kwargs):
- return [
- checks.Warning(
- 'Setting unique=True on a ForeignKey has the same effect as using a OneToOneField.',
- hint='ForeignKey(unique=True) is usually better served by a OneToOneField.',
- obj=self,
- id='fields.W342',
- )
- ] if self.unique else []
+ return (
+ [
+ checks.Warning(
+ "Setting unique=True on a ForeignKey has the same effect as using a OneToOneField.",
+ hint="ForeignKey(unique=True) is usually better served by a OneToOneField.",
+ obj=self,
+ id="fields.W342",
+ )
+ ]
+ if self.unique
+ else []
+ )
def deconstruct(self):
name, path, args, kwargs = super().deconstruct()
- del kwargs['to_fields']
- del kwargs['from_fields']
+ del kwargs["to_fields"]
+ del kwargs["from_fields"]
# Handle the simpler arguments
if self.db_index:
- del kwargs['db_index']
+ del kwargs["db_index"]
else:
- kwargs['db_index'] = False
+ kwargs["db_index"] = False
if self.db_constraint is not True:
- kwargs['db_constraint'] = self.db_constraint
+ kwargs["db_constraint"] = self.db_constraint
# Rel needs more work.
to_meta = getattr(self.remote_field.model, "_meta", None)
if self.remote_field.field_name and (
- not to_meta or (to_meta.pk and self.remote_field.field_name != to_meta.pk.name)):
- kwargs['to_field'] = self.remote_field.field_name
+ not to_meta
+ or (to_meta.pk and self.remote_field.field_name != to_meta.pk.name)
+ ):
+ kwargs["to_field"] = self.remote_field.field_name
return name, path, args, kwargs
def to_python(self, value):
@@ -940,15 +1049,17 @@ class ForeignKey(ForeignObject):
"""Get path from the related model to this field's model."""
opts = self.model._meta
from_opts = self.remote_field.model._meta
- return [PathInfo(
- from_opts=from_opts,
- to_opts=opts,
- target_fields=(opts.pk,),
- join_field=self.remote_field,
- m2m=not self.unique,
- direct=False,
- filtered_relation=filtered_relation,
- )]
+ return [
+ PathInfo(
+ from_opts=from_opts,
+ to_opts=opts,
+ target_fields=(opts.pk,),
+ join_field=self.remote_field,
+ m2m=not self.unique,
+ direct=False,
+ filtered_relation=filtered_relation,
+ )
+ ]
def validate(self, value, model_instance):
if self.remote_field.parent_link:
@@ -964,21 +1075,27 @@ class ForeignKey(ForeignObject):
qs = qs.complex_filter(self.get_limit_choices_to())
if not qs.exists():
raise exceptions.ValidationError(
- self.error_messages['invalid'],
- code='invalid',
+ self.error_messages["invalid"],
+ code="invalid",
params={
- 'model': self.remote_field.model._meta.verbose_name, 'pk': value,
- 'field': self.remote_field.field_name, 'value': value,
+ "model": self.remote_field.model._meta.verbose_name,
+ "pk": value,
+ "field": self.remote_field.field_name,
+ "value": value,
}, # 'pk' is included for backwards compatibility
)
def resolve_related_fields(self):
related_fields = super().resolve_related_fields()
for from_field, to_field in related_fields:
- if to_field and to_field.model != self.remote_field.model._meta.concrete_model:
+ if (
+ to_field
+ and to_field.model != self.remote_field.model._meta.concrete_model
+ ):
raise exceptions.FieldError(
"'%s.%s' refers to field '%s' which is not local to model "
- "'%s'." % (
+ "'%s'."
+ % (
self.model._meta.label,
self.name,
to_field.name,
@@ -988,7 +1105,7 @@ class ForeignKey(ForeignObject):
return related_fields
def get_attname(self):
- return '%s_id' % self.name
+ return "%s_id" % self.name
def get_attname_column(self):
attname = self.get_attname()
@@ -1003,9 +1120,13 @@ class ForeignKey(ForeignObject):
return field_default
def get_db_prep_save(self, value, connection):
- if value is None or (value == '' and
- (not self.target_field.empty_strings_allowed or
- connection.features.interprets_empty_strings_as_nulls)):
+ if value is None or (
+ value == ""
+ and (
+ not self.target_field.empty_strings_allowed
+ or connection.features.interprets_empty_strings_as_nulls
+ )
+ ):
return None
else:
return self.target_field.get_db_prep_save(value, connection=connection)
@@ -1023,16 +1144,20 @@ class ForeignKey(ForeignObject):
def formfield(self, *, using=None, **kwargs):
if isinstance(self.remote_field.model, str):
- raise ValueError("Cannot create form field for %r yet, because "
- "its related model %r has not been loaded yet" %
- (self.name, self.remote_field.model))
- return super().formfield(**{
- 'form_class': forms.ModelChoiceField,
- 'queryset': self.remote_field.model._default_manager.using(using),
- 'to_field_name': self.remote_field.field_name,
- **kwargs,
- 'blank': self.blank,
- })
+ raise ValueError(
+ "Cannot create form field for %r yet, because "
+ "its related model %r has not been loaded yet"
+ % (self.name, self.remote_field.model)
+ )
+ return super().formfield(
+ **{
+ "form_class": forms.ModelChoiceField,
+ "queryset": self.remote_field.model._default_manager.using(using),
+ "to_field_name": self.remote_field.field_name,
+ **kwargs,
+ "blank": self.blank,
+ }
+ )
def db_check(self, connection):
return None
@@ -1060,7 +1185,7 @@ class ForeignKey(ForeignObject):
while isinstance(output_field, ForeignKey):
output_field = output_field.target_field
if output_field is self:
- raise ValueError('Cannot resolve output_field.')
+ raise ValueError("Cannot resolve output_field.")
return super().get_col(alias, output_field)
@@ -1085,13 +1210,13 @@ class OneToOneField(ForeignKey):
description = _("One-to-one relationship")
def __init__(self, to, on_delete, to_field=None, **kwargs):
- kwargs['unique'] = True
+ kwargs["unique"] = True
super().__init__(to, on_delete, to_field=to_field, **kwargs)
def deconstruct(self):
name, path, args, kwargs = super().deconstruct()
if "unique" in kwargs:
- del kwargs['unique']
+ del kwargs["unique"]
return name, path, args, kwargs
def formfield(self, **kwargs):
@@ -1121,44 +1246,54 @@ def create_many_to_many_intermediary_model(field, klass):
through._meta.managed = model._meta.managed or related._meta.managed
to_model = resolve_relation(klass, field.remote_field.model)
- name = '%s_%s' % (klass._meta.object_name, field.name)
+ name = "%s_%s" % (klass._meta.object_name, field.name)
lazy_related_operation(set_managed, klass, to_model, name)
to = make_model_tuple(to_model)[1]
from_ = klass._meta.model_name
if to == from_:
- to = 'to_%s' % to
- from_ = 'from_%s' % from_
+ to = "to_%s" % to
+ from_ = "from_%s" % from_
- meta = type('Meta', (), {
- 'db_table': field._get_m2m_db_table(klass._meta),
- 'auto_created': klass,
- 'app_label': klass._meta.app_label,
- 'db_tablespace': klass._meta.db_tablespace,
- 'unique_together': (from_, to),
- 'verbose_name': _('%(from)s-%(to)s relationship') % {'from': from_, 'to': to},
- 'verbose_name_plural': _('%(from)s-%(to)s relationships') % {'from': from_, 'to': to},
- 'apps': field.model._meta.apps,
- })
+ meta = type(
+ "Meta",
+ (),
+ {
+ "db_table": field._get_m2m_db_table(klass._meta),
+ "auto_created": klass,
+ "app_label": klass._meta.app_label,
+ "db_tablespace": klass._meta.db_tablespace,
+ "unique_together": (from_, to),
+ "verbose_name": _("%(from)s-%(to)s relationship")
+ % {"from": from_, "to": to},
+ "verbose_name_plural": _("%(from)s-%(to)s relationships")
+ % {"from": from_, "to": to},
+ "apps": field.model._meta.apps,
+ },
+ )
# Construct and return the new class.
- return type(name, (models.Model,), {
- 'Meta': meta,
- '__module__': klass.__module__,
- from_: models.ForeignKey(
- klass,
- related_name='%s+' % name,
- db_tablespace=field.db_tablespace,
- db_constraint=field.remote_field.db_constraint,
- on_delete=CASCADE,
- ),
- to: models.ForeignKey(
- to_model,
- related_name='%s+' % name,
- db_tablespace=field.db_tablespace,
- db_constraint=field.remote_field.db_constraint,
- on_delete=CASCADE,
- )
- })
+ return type(
+ name,
+ (models.Model,),
+ {
+ "Meta": meta,
+ "__module__": klass.__module__,
+ from_: models.ForeignKey(
+ klass,
+ related_name="%s+" % name,
+ db_tablespace=field.db_tablespace,
+ db_constraint=field.remote_field.db_constraint,
+ on_delete=CASCADE,
+ ),
+ to: models.ForeignKey(
+ to_model,
+ related_name="%s+" % name,
+ db_tablespace=field.db_tablespace,
+ db_constraint=field.remote_field.db_constraint,
+ on_delete=CASCADE,
+ ),
+ },
+ )
class ManyToManyField(RelatedField):
@@ -1181,31 +1316,45 @@ class ManyToManyField(RelatedField):
description = _("Many-to-many relationship")
- def __init__(self, to, related_name=None, related_query_name=None,
- limit_choices_to=None, symmetrical=None, through=None,
- through_fields=None, db_constraint=True, db_table=None,
- swappable=True, **kwargs):
+ def __init__(
+ self,
+ to,
+ related_name=None,
+ related_query_name=None,
+ limit_choices_to=None,
+ symmetrical=None,
+ through=None,
+ through_fields=None,
+ db_constraint=True,
+ db_table=None,
+ swappable=True,
+ **kwargs,
+ ):
try:
to._meta
except AttributeError:
if not isinstance(to, str):
raise TypeError(
- '%s(%r) is invalid. First parameter to ManyToManyField '
- 'must be either a model, a model name, or the string %r' % (
- self.__class__.__name__, to, RECURSIVE_RELATIONSHIP_CONSTANT,
+ "%s(%r) is invalid. First parameter to ManyToManyField "
+ "must be either a model, a model name, or the string %r"
+ % (
+ self.__class__.__name__,
+ to,
+ RECURSIVE_RELATIONSHIP_CONSTANT,
)
)
if symmetrical is None:
- symmetrical = (to == RECURSIVE_RELATIONSHIP_CONSTANT)
+ symmetrical = to == RECURSIVE_RELATIONSHIP_CONSTANT
if through is not None and db_table is not None:
raise ValueError(
- 'Cannot specify a db_table if an intermediary model is used.'
+ "Cannot specify a db_table if an intermediary model is used."
)
- kwargs['rel'] = self.rel_class(
- self, to,
+ kwargs["rel"] = self.rel_class(
+ self,
+ to,
related_name=related_name,
related_query_name=related_query_name,
limit_choices_to=limit_choices_to,
@@ -1214,7 +1363,7 @@ class ManyToManyField(RelatedField):
through_fields=through_fields,
db_constraint=db_constraint,
)
- self.has_null_arg = 'null' in kwargs
+ self.has_null_arg = "null" in kwargs
super().__init__(
related_name=related_name,
@@ -1239,9 +1388,9 @@ class ManyToManyField(RelatedField):
if self.unique:
return [
checks.Error(
- 'ManyToManyFields cannot be unique.',
+ "ManyToManyFields cannot be unique.",
obj=self,
- id='fields.E330',
+ id="fields.E330",
)
]
return []
@@ -1252,49 +1401,53 @@ class ManyToManyField(RelatedField):
if self.has_null_arg:
warnings.append(
checks.Warning(
- 'null has no effect on ManyToManyField.',
+ "null has no effect on ManyToManyField.",
obj=self,
- id='fields.W340',
+ id="fields.W340",
)
)
if self._validators:
warnings.append(
checks.Warning(
- 'ManyToManyField does not support validators.',
+ "ManyToManyField does not support validators.",
obj=self,
- id='fields.W341',
+ id="fields.W341",
)
)
if self.remote_field.symmetrical and self._related_name:
warnings.append(
checks.Warning(
- 'related_name has no effect on ManyToManyField '
+ "related_name has no effect on ManyToManyField "
'with a symmetrical relationship, e.g. to "self".',
obj=self,
- id='fields.W345',
+ id="fields.W345",
)
)
return warnings
def _check_relationship_model(self, from_model=None, **kwargs):
- if hasattr(self.remote_field.through, '_meta'):
+ if hasattr(self.remote_field.through, "_meta"):
qualified_model_name = "%s.%s" % (
- self.remote_field.through._meta.app_label, self.remote_field.through.__name__)
+ self.remote_field.through._meta.app_label,
+ self.remote_field.through.__name__,
+ )
else:
qualified_model_name = self.remote_field.through
errors = []
- if self.remote_field.through not in self.opts.apps.get_models(include_auto_created=True):
+ if self.remote_field.through not in self.opts.apps.get_models(
+ include_auto_created=True
+ ):
# The relationship model is not installed.
errors.append(
checks.Error(
"Field specifies a many-to-many relation through model "
"'%s', which has not been installed." % qualified_model_name,
obj=self,
- id='fields.E331',
+ id="fields.E331",
)
)
@@ -1316,7 +1469,7 @@ class ManyToManyField(RelatedField):
# Count foreign keys in intermediate model
if self_referential:
seen_self = sum(
- from_model == getattr(field.remote_field, 'model', None)
+ from_model == getattr(field.remote_field, "model", None)
for field in self.remote_field.through._meta.fields
)
@@ -1327,41 +1480,46 @@ class ManyToManyField(RelatedField):
"'%s', but it has more than two foreign keys "
"to '%s', which is ambiguous. You must specify "
"which two foreign keys Django should use via the "
- "through_fields keyword argument." % (self, from_model_name),
+ "through_fields keyword argument."
+ % (self, from_model_name),
hint="Use through_fields to specify which two foreign keys Django should use.",
obj=self.remote_field.through,
- id='fields.E333',
+ id="fields.E333",
)
)
else:
# Count foreign keys in relationship model
seen_from = sum(
- from_model == getattr(field.remote_field, 'model', None)
+ from_model == getattr(field.remote_field, "model", None)
for field in self.remote_field.through._meta.fields
)
seen_to = sum(
- to_model == getattr(field.remote_field, 'model', None)
+ to_model == getattr(field.remote_field, "model", None)
for field in self.remote_field.through._meta.fields
)
if seen_from > 1 and not self.remote_field.through_fields:
errors.append(
checks.Error(
- ("The model is used as an intermediate model by "
- "'%s', but it has more than one foreign key "
- "from '%s', which is ambiguous. You must specify "
- "which foreign key Django should use via the "
- "through_fields keyword argument.") % (self, from_model_name),
+ (
+ "The model is used as an intermediate model by "
+ "'%s', but it has more than one foreign key "
+ "from '%s', which is ambiguous. You must specify "
+ "which foreign key Django should use via the "
+ "through_fields keyword argument."
+ )
+ % (self, from_model_name),
hint=(
- 'If you want to create a recursive relationship, '
+ "If you want to create a recursive relationship, "
'use ManyToManyField("%s", through="%s").'
- ) % (
+ )
+ % (
RECURSIVE_RELATIONSHIP_CONSTANT,
relationship_model_name,
),
obj=self,
- id='fields.E334',
+ id="fields.E334",
)
)
@@ -1374,14 +1532,15 @@ class ManyToManyField(RelatedField):
"which foreign key Django should use via the "
"through_fields keyword argument." % (self, to_model_name),
hint=(
- 'If you want to create a recursive relationship, '
+ "If you want to create a recursive relationship, "
'use ManyToManyField("%s", through="%s").'
- ) % (
+ )
+ % (
RECURSIVE_RELATIONSHIP_CONSTANT,
relationship_model_name,
),
obj=self,
- id='fields.E335',
+ id="fields.E335",
)
)
@@ -1389,11 +1548,10 @@ class ManyToManyField(RelatedField):
errors.append(
checks.Error(
"The model is used as an intermediate model by "
- "'%s', but it does not have a foreign key to '%s' or '%s'." % (
- self, from_model_name, to_model_name
- ),
+ "'%s', but it does not have a foreign key to '%s' or '%s'."
+ % (self, from_model_name, to_model_name),
obj=self.remote_field.through,
- id='fields.E336',
+ id="fields.E336",
)
)
@@ -1401,8 +1559,11 @@ class ManyToManyField(RelatedField):
if self.remote_field.through_fields is not None:
# Validate that we're given an iterable of at least two items
# and that none of them is "falsy".
- if not (len(self.remote_field.through_fields) >= 2 and
- self.remote_field.through_fields[0] and self.remote_field.through_fields[1]):
+ if not (
+ len(self.remote_field.through_fields) >= 2
+ and self.remote_field.through_fields[0]
+ and self.remote_field.through_fields[1]
+ ):
errors.append(
checks.Error(
"Field specifies 'through_fields' but does not provide "
@@ -1410,7 +1571,7 @@ class ManyToManyField(RelatedField):
"for the relation through model '%s'." % qualified_model_name,
hint="Make sure you specify 'through_fields' as through_fields=('field1', 'field2')",
obj=self,
- id='fields.E337',
+ id="fields.E337",
)
)
@@ -1424,20 +1585,34 @@ class ManyToManyField(RelatedField):
"where the field is attached to."
)
- source, through, target = from_model, self.remote_field.through, self.remote_field.model
- source_field_name, target_field_name = self.remote_field.through_fields[:2]
+ source, through, target = (
+ from_model,
+ self.remote_field.through,
+ self.remote_field.model,
+ )
+ source_field_name, target_field_name = self.remote_field.through_fields[
+ :2
+ ]
- for field_name, related_model in ((source_field_name, source),
- (target_field_name, target)):
+ for field_name, related_model in (
+ (source_field_name, source),
+ (target_field_name, target),
+ ):
possible_field_names = []
for f in through._meta.fields:
- if hasattr(f, 'remote_field') and getattr(f.remote_field, 'model', None) == related_model:
+ if (
+ hasattr(f, "remote_field")
+ and getattr(f.remote_field, "model", None) == related_model
+ ):
possible_field_names.append(f.name)
if possible_field_names:
- hint = "Did you mean one of the following foreign keys to '%s': %s?" % (
- related_model._meta.object_name,
- ', '.join(possible_field_names),
+ hint = (
+ "Did you mean one of the following foreign keys to '%s': %s?"
+ % (
+ related_model._meta.object_name,
+ ", ".join(possible_field_names),
+ )
)
else:
hint = None
@@ -1451,28 +1626,36 @@ class ManyToManyField(RelatedField):
% (qualified_model_name, field_name),
hint=hint,
obj=self,
- id='fields.E338',
+ id="fields.E338",
)
)
else:
- if not (hasattr(field, 'remote_field') and
- getattr(field.remote_field, 'model', None) == related_model):
+ if not (
+ hasattr(field, "remote_field")
+ and getattr(field.remote_field, "model", None)
+ == related_model
+ ):
errors.append(
checks.Error(
- "'%s.%s' is not a foreign key to '%s'." % (
- through._meta.object_name, field_name,
+ "'%s.%s' is not a foreign key to '%s'."
+ % (
+ through._meta.object_name,
+ field_name,
related_model._meta.object_name,
),
hint=hint,
obj=self,
- id='fields.E339',
+ id="fields.E339",
)
)
return errors
def _check_table_uniqueness(self, **kwargs):
- if isinstance(self.remote_field.through, str) or not self.remote_field.through._meta.managed:
+ if (
+ isinstance(self.remote_field.through, str)
+ or not self.remote_field.through._meta.managed
+ ):
return []
registered_tables = {
model._meta.db_table: model
@@ -1483,25 +1666,31 @@ class ManyToManyField(RelatedField):
model = registered_tables.get(m2m_db_table)
# The second condition allows multiple m2m relations on a model if
# some point to a through model that proxies another through model.
- if model and model._meta.concrete_model != self.remote_field.through._meta.concrete_model:
+ if (
+ model
+ and model._meta.concrete_model
+ != self.remote_field.through._meta.concrete_model
+ ):
if model._meta.auto_created:
+
def _get_field_name(model):
for field in model._meta.auto_created._meta.many_to_many:
if field.remote_field.through is model:
return field.name
+
opts = model._meta.auto_created._meta
- clashing_obj = '%s.%s' % (opts.label, _get_field_name(model))
+ clashing_obj = "%s.%s" % (opts.label, _get_field_name(model))
else:
clashing_obj = model._meta.label
if settings.DATABASE_ROUTERS:
- error_class, error_id = checks.Warning, 'fields.W344'
+ error_class, error_id = checks.Warning, "fields.W344"
error_hint = (
- 'You have configured settings.DATABASE_ROUTERS. Verify '
- 'that the table of %r is correctly routed to a separate '
- 'database.' % clashing_obj
+ "You have configured settings.DATABASE_ROUTERS. Verify "
+ "that the table of %r is correctly routed to a separate "
+ "database." % clashing_obj
)
else:
- error_class, error_id = checks.Error, 'fields.E340'
+ error_class, error_id = checks.Error, "fields.E340"
error_hint = None
return [
error_class(
@@ -1518,34 +1707,34 @@ class ManyToManyField(RelatedField):
name, path, args, kwargs = super().deconstruct()
# Handle the simpler arguments.
if self.db_table is not None:
- kwargs['db_table'] = self.db_table
+ kwargs["db_table"] = self.db_table
if self.remote_field.db_constraint is not True:
- kwargs['db_constraint'] = self.remote_field.db_constraint
+ kwargs["db_constraint"] = self.remote_field.db_constraint
# Rel needs more work.
if isinstance(self.remote_field.model, str):
- kwargs['to'] = self.remote_field.model
+ kwargs["to"] = self.remote_field.model
else:
- kwargs['to'] = self.remote_field.model._meta.label
- if getattr(self.remote_field, 'through', None) is not None:
+ kwargs["to"] = self.remote_field.model._meta.label
+ if getattr(self.remote_field, "through", None) is not None:
if isinstance(self.remote_field.through, str):
- kwargs['through'] = self.remote_field.through
+ kwargs["through"] = self.remote_field.through
elif not self.remote_field.through._meta.auto_created:
- kwargs['through'] = self.remote_field.through._meta.label
+ kwargs["through"] = self.remote_field.through._meta.label
# If swappable is True, then see if we're actually pointing to the target
# of a swap.
swappable_setting = self.swappable_setting
if swappable_setting is not None:
# If it's already a settings reference, error.
- if hasattr(kwargs['to'], "setting_name"):
- if kwargs['to'].setting_name != swappable_setting:
+ if hasattr(kwargs["to"], "setting_name"):
+ if kwargs["to"].setting_name != swappable_setting:
raise ValueError(
"Cannot deconstruct a ManyToManyField pointing to a "
"model that is swapped in place of more than one model "
- "(%s and %s)" % (kwargs['to'].setting_name, swappable_setting)
+ "(%s and %s)" % (kwargs["to"].setting_name, swappable_setting)
)
- kwargs['to'] = SettingsReference(
- kwargs['to'],
+ kwargs["to"] = SettingsReference(
+ kwargs["to"],
swappable_setting,
)
return name, path, args, kwargs
@@ -1605,7 +1794,7 @@ class ManyToManyField(RelatedField):
elif self.db_table:
return self.db_table
else:
- m2m_table_name = '%s_%s' % (utils.strip_quotes(opts.db_table), self.name)
+ m2m_table_name = "%s_%s" % (utils.strip_quotes(opts.db_table), self.name)
return utils.truncate_name(m2m_table_name, connection.ops.max_name_length())
def _get_m2m_attr(self, related, attr):
@@ -1613,7 +1802,7 @@ class ManyToManyField(RelatedField):
Function that can be curried to provide the source accessor or DB
column name for the m2m table.
"""
- cache_attr = '_m2m_%s_cache' % attr
+ cache_attr = "_m2m_%s_cache" % attr
if hasattr(self, cache_attr):
return getattr(self, cache_attr)
if self.remote_field.through_fields is not None:
@@ -1621,8 +1810,11 @@ class ManyToManyField(RelatedField):
else:
link_field_name = None
for f in self.remote_field.through._meta.fields:
- if (f.is_relation and f.remote_field.model == related.related_model and
- (link_field_name is None or link_field_name == f.name)):
+ if (
+ f.is_relation
+ and f.remote_field.model == related.related_model
+ and (link_field_name is None or link_field_name == f.name)
+ ):
setattr(self, cache_attr, getattr(f, attr))
return getattr(self, cache_attr)
@@ -1631,7 +1823,7 @@ class ManyToManyField(RelatedField):
Function that can be curried to provide the related accessor or DB
column name for the m2m table.
"""
- cache_attr = '_m2m_reverse_%s_cache' % attr
+ cache_attr = "_m2m_reverse_%s_cache" % attr
if hasattr(self, cache_attr):
return getattr(self, cache_attr)
found = False
@@ -1664,8 +1856,8 @@ class ManyToManyField(RelatedField):
# automatically. The funky name reduces the chance of an accidental
# clash.
if self.remote_field.symmetrical and (
- self.remote_field.model == RECURSIVE_RELATIONSHIP_CONSTANT or
- self.remote_field.model == cls._meta.object_name
+ self.remote_field.model == RECURSIVE_RELATIONSHIP_CONSTANT
+ or self.remote_field.model == cls._meta.object_name
):
self.remote_field.related_name = "%s_rel_+" % name
elif self.remote_field.is_hidden():
@@ -1673,7 +1865,7 @@ class ManyToManyField(RelatedField):
# related_name with one generated from the m2m field name. Django
# still uses backwards relations internally and we need to avoid
# clashes between multiple m2m fields with related_name == '+'.
- self.remote_field.related_name = '_%s_%s_%s_+' % (
+ self.remote_field.related_name = "_%s_%s_%s_+" % (
cls._meta.app_label,
cls.__name__.lower(),
name,
@@ -1687,11 +1879,17 @@ class ManyToManyField(RelatedField):
# 3) The class owning the m2m field has been swapped out.
if not cls._meta.abstract:
if self.remote_field.through:
+
def resolve_through_model(_, model, field):
field.remote_field.through = model
- lazy_related_operation(resolve_through_model, cls, self.remote_field.through, field=self)
+
+ lazy_related_operation(
+ resolve_through_model, cls, self.remote_field.through, field=self
+ )
elif not cls._meta.swapped:
- self.remote_field.through = create_many_to_many_intermediary_model(self, cls)
+ self.remote_field.through = create_many_to_many_intermediary_model(
+ self, cls
+ )
# Add the descriptor for the m2m relation.
setattr(cls, self.name, ManyToManyDescriptor(self.remote_field, reverse=False))
@@ -1702,19 +1900,30 @@ class ManyToManyField(RelatedField):
def contribute_to_related_class(self, cls, related):
# Internal M2Ms (i.e., those with a related name ending with '+')
# and swapped models don't get a related descriptor.
- if not self.remote_field.is_hidden() and not related.related_model._meta.swapped:
- setattr(cls, related.get_accessor_name(), ManyToManyDescriptor(self.remote_field, reverse=True))
+ if (
+ not self.remote_field.is_hidden()
+ and not related.related_model._meta.swapped
+ ):
+ setattr(
+ cls,
+ related.get_accessor_name(),
+ ManyToManyDescriptor(self.remote_field, reverse=True),
+ )
# Set up the accessors for the column names on the m2m table.
- self.m2m_column_name = partial(self._get_m2m_attr, related, 'column')
- self.m2m_reverse_name = partial(self._get_m2m_reverse_attr, related, 'column')
+ self.m2m_column_name = partial(self._get_m2m_attr, related, "column")
+ self.m2m_reverse_name = partial(self._get_m2m_reverse_attr, related, "column")
- self.m2m_field_name = partial(self._get_m2m_attr, related, 'name')
- self.m2m_reverse_field_name = partial(self._get_m2m_reverse_attr, related, 'name')
+ self.m2m_field_name = partial(self._get_m2m_attr, related, "name")
+ self.m2m_reverse_field_name = partial(
+ self._get_m2m_reverse_attr, related, "name"
+ )
- get_m2m_rel = partial(self._get_m2m_attr, related, 'remote_field')
+ get_m2m_rel = partial(self._get_m2m_attr, related, "remote_field")
self.m2m_target_field_name = lambda: get_m2m_rel().field_name
- get_m2m_reverse_rel = partial(self._get_m2m_reverse_attr, related, 'remote_field')
+ get_m2m_reverse_rel = partial(
+ self._get_m2m_reverse_attr, related, "remote_field"
+ )
self.m2m_reverse_target_field_name = lambda: get_m2m_reverse_rel().field_name
def set_attributes_from_rel(self):
@@ -1728,17 +1937,17 @@ class ManyToManyField(RelatedField):
def formfield(self, *, using=None, **kwargs):
defaults = {
- 'form_class': forms.ModelMultipleChoiceField,
- 'queryset': self.remote_field.model._default_manager.using(using),
+ "form_class": forms.ModelMultipleChoiceField,
+ "queryset": self.remote_field.model._default_manager.using(using),
**kwargs,
}
# If initial is passed in, it's a list of related objects, but the
# MultipleChoiceField takes a list of IDs.
- if defaults.get('initial') is not None:
- initial = defaults['initial']
+ if defaults.get("initial") is not None:
+ initial = defaults["initial"]
if callable(initial):
initial = initial()
- defaults['initial'] = [i.pk for i in initial]
+ defaults["initial"] = [i.pk for i in initial]
return super().formfield(**defaults)
def db_check(self, connection):
diff --git a/django/db/models/fields/related_descriptors.py b/django/db/models/fields/related_descriptors.py
index 9c50ef16ce..3f67ed8166 100644
--- a/django/db/models/fields/related_descriptors.py
+++ b/django/db/models/fields/related_descriptors.py
@@ -74,7 +74,9 @@ from django.utils.functional import cached_property
class ForeignKeyDeferredAttribute(DeferredAttribute):
def __set__(self, instance, value):
- if instance.__dict__.get(self.field.attname) != value and self.field.is_cached(instance):
+ if instance.__dict__.get(self.field.attname) != value and self.field.is_cached(
+ instance
+ ):
self.field.delete_cached_value(instance)
instance.__dict__[self.field.attname] = value
@@ -101,14 +103,16 @@ class ForwardManyToOneDescriptor:
# related model might not be resolved yet; `self.field.model` might
# still be a string model reference.
return type(
- 'RelatedObjectDoesNotExist',
- (self.field.remote_field.model.DoesNotExist, AttributeError), {
- '__module__': self.field.model.__module__,
- '__qualname__': '%s.%s.RelatedObjectDoesNotExist' % (
+ "RelatedObjectDoesNotExist",
+ (self.field.remote_field.model.DoesNotExist, AttributeError),
+ {
+ "__module__": self.field.model.__module__,
+ "__qualname__": "%s.%s.RelatedObjectDoesNotExist"
+ % (
self.field.model.__qualname__,
self.field.name,
),
- }
+ },
)
def is_cached(self, instance):
@@ -135,9 +139,12 @@ class ForwardManyToOneDescriptor:
# The check for len(...) == 1 is a special case that allows the query
# to be join-less and smaller. Refs #21760.
if remote_field.is_hidden() or len(self.field.foreign_related_fields) == 1:
- query = {'%s__in' % related_field.name: {instance_attr(inst)[0] for inst in instances}}
+ query = {
+ "%s__in"
+ % related_field.name: {instance_attr(inst)[0] for inst in instances}
+ }
else:
- query = {'%s__in' % self.field.related_query_name(): instances}
+ query = {"%s__in" % self.field.related_query_name(): instances}
queryset = queryset.filter(**query)
# Since we're going to assign directly in the cache,
@@ -146,7 +153,14 @@ class ForwardManyToOneDescriptor:
for rel_obj in queryset:
instance = instances_dict[rel_obj_attr(rel_obj)]
remote_field.set_cached_value(rel_obj, instance)
- return queryset, rel_obj_attr, instance_attr, True, self.field.get_cache_name(), False
+ return (
+ queryset,
+ rel_obj_attr,
+ instance_attr,
+ True,
+ self.field.get_cache_name(),
+ False,
+ )
def get_object(self, instance):
qs = self.get_queryset(instance=instance)
@@ -173,7 +187,11 @@ class ForwardManyToOneDescriptor:
rel_obj = self.field.get_cached_value(instance)
except KeyError:
has_value = None not in self.field.get_local_related_value(instance)
- ancestor_link = instance._meta.get_ancestor_link(self.field.model) if has_value else None
+ ancestor_link = (
+ instance._meta.get_ancestor_link(self.field.model)
+ if has_value
+ else None
+ )
if ancestor_link and ancestor_link.is_cached(instance):
# An ancestor link will exist if this field is defined on a
# multi-table inheritance parent of the instance's class.
@@ -211,9 +229,12 @@ class ForwardManyToOneDescriptor:
- ``value`` is the ``parent`` instance on the right of the equal sign
"""
# An object must be an instance of the related class.
- if value is not None and not isinstance(value, self.field.remote_field.model._meta.concrete_model):
+ if value is not None and not isinstance(
+ value, self.field.remote_field.model._meta.concrete_model
+ ):
raise ValueError(
- 'Cannot assign "%r": "%s.%s" must be a "%s" instance.' % (
+ 'Cannot assign "%r": "%s.%s" must be a "%s" instance.'
+ % (
value,
instance._meta.object_name,
self.field.name,
@@ -222,11 +243,18 @@ class ForwardManyToOneDescriptor:
)
elif value is not None:
if instance._state.db is None:
- instance._state.db = router.db_for_write(instance.__class__, instance=value)
+ instance._state.db = router.db_for_write(
+ instance.__class__, instance=value
+ )
if value._state.db is None:
- value._state.db = router.db_for_write(value.__class__, instance=instance)
+ value._state.db = router.db_for_write(
+ value.__class__, instance=instance
+ )
if not router.allow_relation(value, instance):
- raise ValueError('Cannot assign "%r": the current database router prevents this relation.' % value)
+ raise ValueError(
+ 'Cannot assign "%r": the current database router prevents this relation.'
+ % value
+ )
remote_field = self.field.remote_field
# If we're setting the value of a OneToOneField to None, we need to clear
@@ -314,12 +342,15 @@ class ForwardOneToOneDescriptor(ForwardManyToOneDescriptor):
opts = instance._meta
# Inherited primary key fields from this object's base classes.
inherited_pk_fields = [
- field for field in opts.concrete_fields
+ field
+ for field in opts.concrete_fields
if field.primary_key and field.remote_field
]
for field in inherited_pk_fields:
rel_model_pk_name = field.remote_field.model._meta.pk.attname
- raw_value = getattr(value, rel_model_pk_name) if value is not None else None
+ raw_value = (
+ getattr(value, rel_model_pk_name) if value is not None else None
+ )
setattr(instance, rel_model_pk_name, raw_value)
@@ -346,13 +377,15 @@ class ReverseOneToOneDescriptor:
# The exception isn't created at initialization time for the sake of
# consistency with `ForwardManyToOneDescriptor`.
return type(
- 'RelatedObjectDoesNotExist',
- (self.related.related_model.DoesNotExist, AttributeError), {
- '__module__': self.related.model.__module__,
- '__qualname__': '%s.%s.RelatedObjectDoesNotExist' % (
+ "RelatedObjectDoesNotExist",
+ (self.related.related_model.DoesNotExist, AttributeError),
+ {
+ "__module__": self.related.model.__module__,
+ "__qualname__": "%s.%s.RelatedObjectDoesNotExist"
+ % (
self.related.model.__qualname__,
self.related.name,
- )
+ ),
},
)
@@ -370,7 +403,7 @@ class ReverseOneToOneDescriptor:
rel_obj_attr = self.related.field.get_local_related_value
instance_attr = self.related.field.get_foreign_related_value
instances_dict = {instance_attr(inst): inst for inst in instances}
- query = {'%s__in' % self.related.field.name: instances}
+ query = {"%s__in" % self.related.field.name: instances}
queryset = queryset.filter(**query)
# Since we're going to assign directly in the cache,
@@ -378,7 +411,14 @@ class ReverseOneToOneDescriptor:
for rel_obj in queryset:
instance = instances_dict[rel_obj_attr(rel_obj)]
self.related.field.set_cached_value(rel_obj, instance)
- return queryset, rel_obj_attr, instance_attr, True, self.related.get_cache_name(), False
+ return (
+ queryset,
+ rel_obj_attr,
+ instance_attr,
+ True,
+ self.related.get_cache_name(),
+ False,
+ )
def __get__(self, instance, cls=None):
"""
@@ -419,10 +459,8 @@ class ReverseOneToOneDescriptor:
if rel_obj is None:
raise self.RelatedObjectDoesNotExist(
- "%s has no %s." % (
- instance.__class__.__name__,
- self.related.get_accessor_name()
- )
+ "%s has no %s."
+ % (instance.__class__.__name__, self.related.get_accessor_name())
)
else:
return rel_obj
@@ -458,7 +496,8 @@ class ReverseOneToOneDescriptor:
elif not isinstance(value, self.related.related_model):
# An object must be an instance of the related class.
raise ValueError(
- 'Cannot assign "%r": "%s.%s" must be a "%s" instance.' % (
+ 'Cannot assign "%r": "%s.%s" must be a "%s" instance.'
+ % (
value,
instance._meta.object_name,
self.related.get_accessor_name(),
@@ -467,13 +506,23 @@ class ReverseOneToOneDescriptor:
)
else:
if instance._state.db is None:
- instance._state.db = router.db_for_write(instance.__class__, instance=value)
+ instance._state.db = router.db_for_write(
+ instance.__class__, instance=value
+ )
if value._state.db is None:
- value._state.db = router.db_for_write(value.__class__, instance=instance)
+ value._state.db = router.db_for_write(
+ value.__class__, instance=instance
+ )
if not router.allow_relation(value, instance):
- raise ValueError('Cannot assign "%r": the current database router prevents this relation.' % value)
+ raise ValueError(
+ 'Cannot assign "%r": the current database router prevents this relation.'
+ % value
+ )
- related_pk = tuple(getattr(instance, field.attname) for field in self.related.field.foreign_related_fields)
+ related_pk = tuple(
+ getattr(instance, field.attname)
+ for field in self.related.field.foreign_related_fields
+ )
# Set the value of the related field to the value of the related object's related field
for index, field in enumerate(self.related.field.local_related_fields):
setattr(value, field.attname, related_pk[index])
@@ -548,13 +597,13 @@ class ReverseManyToOneDescriptor:
def _get_set_deprecation_msg_params(self):
return (
- 'reverse side of a related set',
+ "reverse side of a related set",
self.rel.get_accessor_name(),
)
def __set__(self, instance, value):
raise TypeError(
- 'Direct assignment to the %s is prohibited. Use %s.set() instead.'
+ "Direct assignment to the %s is prohibited. Use %s.set() instead."
% self._get_set_deprecation_msg_params(),
)
@@ -581,6 +630,7 @@ def create_reverse_many_to_one_manager(superclass, rel):
manager = getattr(self.model, manager)
manager_class = create_reverse_many_to_one_manager(manager.__class__, rel)
return manager_class(self.instance)
+
do_not_call_in_templates = True
def _apply_rel_filters(self, queryset):
@@ -588,7 +638,9 @@ def create_reverse_many_to_one_manager(superclass, rel):
Filter the queryset for the instance this manager is bound to.
"""
db = self._db or router.db_for_read(self.model, instance=self.instance)
- empty_strings_as_null = connections[db].features.interprets_empty_strings_as_nulls
+ empty_strings_as_null = connections[
+ db
+ ].features.interprets_empty_strings_as_nulls
queryset._add_hints(instance=self.instance)
if self._db:
queryset = queryset.using(self._db)
@@ -596,7 +648,7 @@ def create_reverse_many_to_one_manager(superclass, rel):
queryset = queryset.filter(**self.core_filters)
for field in self.field.foreign_related_fields:
val = getattr(self.instance, field.attname)
- if val is None or (val == '' and empty_strings_as_null):
+ if val is None or (val == "" and empty_strings_as_null):
return queryset.none()
if self.field.many_to_one:
# Guard against field-like objects such as GenericRelation
@@ -608,24 +660,32 @@ def create_reverse_many_to_one_manager(superclass, rel):
except FieldError:
# The relationship has multiple target fields. Use a tuple
# for related object id.
- rel_obj_id = tuple([
- getattr(self.instance, target_field.attname)
- for target_field in self.field.path_infos[-1].target_fields
- ])
+ rel_obj_id = tuple(
+ [
+ getattr(self.instance, target_field.attname)
+ for target_field in self.field.path_infos[-1].target_fields
+ ]
+ )
else:
rel_obj_id = getattr(self.instance, target_field.attname)
- queryset._known_related_objects = {self.field: {rel_obj_id: self.instance}}
+ queryset._known_related_objects = {
+ self.field: {rel_obj_id: self.instance}
+ }
return queryset
def _remove_prefetched_objects(self):
try:
- self.instance._prefetched_objects_cache.pop(self.field.remote_field.get_cache_name())
+ self.instance._prefetched_objects_cache.pop(
+ self.field.remote_field.get_cache_name()
+ )
except (AttributeError, KeyError):
pass # nothing to clear from cache
def get_queryset(self):
try:
- return self.instance._prefetched_objects_cache[self.field.remote_field.get_cache_name()]
+ return self.instance._prefetched_objects_cache[
+ self.field.remote_field.get_cache_name()
+ ]
except (AttributeError, KeyError):
queryset = super().get_queryset()
return self._apply_rel_filters(queryset)
@@ -640,7 +700,7 @@ def create_reverse_many_to_one_manager(superclass, rel):
rel_obj_attr = self.field.get_local_related_value
instance_attr = self.field.get_foreign_related_value
instances_dict = {instance_attr(inst): inst for inst in instances}
- query = {'%s__in' % self.field.name: instances}
+ query = {"%s__in" % self.field.name: instances}
queryset = queryset.filter(**query)
# Since we just bypassed this class' get_queryset(), we must manage
@@ -658,9 +718,13 @@ def create_reverse_many_to_one_manager(superclass, rel):
def check_and_update_obj(obj):
if not isinstance(obj, self.model):
- raise TypeError("'%s' instance expected, got %r" % (
- self.model._meta.object_name, obj,
- ))
+ raise TypeError(
+ "'%s' instance expected, got %r"
+ % (
+ self.model._meta.object_name,
+ obj,
+ )
+ )
setattr(obj, self.field.name, self.instance)
if bulk:
@@ -673,36 +737,43 @@ def create_reverse_many_to_one_manager(superclass, rel):
"the object first." % obj
)
pks.append(obj.pk)
- self.model._base_manager.using(db).filter(pk__in=pks).update(**{
- self.field.name: self.instance,
- })
+ self.model._base_manager.using(db).filter(pk__in=pks).update(
+ **{
+ self.field.name: self.instance,
+ }
+ )
else:
with transaction.atomic(using=db, savepoint=False):
for obj in objs:
check_and_update_obj(obj)
obj.save()
+
add.alters_data = True
def create(self, **kwargs):
kwargs[self.field.name] = self.instance
db = router.db_for_write(self.model, instance=self.instance)
return super(RelatedManager, self.db_manager(db)).create(**kwargs)
+
create.alters_data = True
def get_or_create(self, **kwargs):
kwargs[self.field.name] = self.instance
db = router.db_for_write(self.model, instance=self.instance)
return super(RelatedManager, self.db_manager(db)).get_or_create(**kwargs)
+
get_or_create.alters_data = True
def update_or_create(self, **kwargs):
kwargs[self.field.name] = self.instance
db = router.db_for_write(self.model, instance=self.instance)
return super(RelatedManager, self.db_manager(db)).update_or_create(**kwargs)
+
update_or_create.alters_data = True
# remove() and clear() are only provided if the ForeignKey can have a value of null.
if rel.field.null:
+
def remove(self, *objs, bulk=True):
if not objs:
return
@@ -710,9 +781,13 @@ def create_reverse_many_to_one_manager(superclass, rel):
old_ids = set()
for obj in objs:
if not isinstance(obj, self.model):
- raise TypeError("'%s' instance expected, got %r" % (
- self.model._meta.object_name, obj,
- ))
+ raise TypeError(
+ "'%s' instance expected, got %r"
+ % (
+ self.model._meta.object_name,
+ obj,
+ )
+ )
# Is obj actually part of this descriptor set?
if self.field.get_local_related_value(obj) == val:
old_ids.add(obj.pk)
@@ -721,10 +796,12 @@ def create_reverse_many_to_one_manager(superclass, rel):
"%r is not related to %r." % (obj, self.instance)
)
self._clear(self.filter(pk__in=old_ids), bulk)
+
remove.alters_data = True
def clear(self, *, bulk=True):
self._clear(self, bulk)
+
clear.alters_data = True
def _clear(self, queryset, bulk):
@@ -739,6 +816,7 @@ def create_reverse_many_to_one_manager(superclass, rel):
for obj in queryset:
setattr(obj, self.field.name, None)
obj.save(update_fields=[self.field.name])
+
_clear.alters_data = True
def set(self, objs, *, bulk=True, clear=False):
@@ -765,6 +843,7 @@ def create_reverse_many_to_one_manager(superclass, rel):
self.add(*new_objs, bulk=bulk)
else:
self.add(*objs, bulk=bulk)
+
set.alters_data = True
return RelatedManager
@@ -822,7 +901,8 @@ class ManyToManyDescriptor(ReverseManyToOneDescriptor):
def _get_set_deprecation_msg_params(self):
return (
- '%s side of a many-to-many set' % ('reverse' if self.reverse else 'forward'),
+ "%s side of a many-to-many set"
+ % ("reverse" if self.reverse else "forward"),
self.rel.get_accessor_name() if self.reverse else self.field.name,
)
@@ -865,41 +945,51 @@ def create_forward_many_to_many_manager(superclass, rel, reverse):
self.core_filters = {}
self.pk_field_names = {}
for lh_field, rh_field in self.source_field.related_fields:
- core_filter_key = '%s__%s' % (self.query_field_name, rh_field.name)
+ core_filter_key = "%s__%s" % (self.query_field_name, rh_field.name)
self.core_filters[core_filter_key] = getattr(instance, rh_field.attname)
self.pk_field_names[lh_field.name] = rh_field.name
self.related_val = self.source_field.get_foreign_related_value(instance)
if None in self.related_val:
- raise ValueError('"%r" needs to have a value for field "%s" before '
- 'this many-to-many relationship can be used.' %
- (instance, self.pk_field_names[self.source_field_name]))
+ raise ValueError(
+ '"%r" needs to have a value for field "%s" before '
+ "this many-to-many relationship can be used."
+ % (instance, self.pk_field_names[self.source_field_name])
+ )
# Even if this relation is not to pk, we require still pk value.
# The wish is that the instance has been already saved to DB,
# although having a pk value isn't a guarantee of that.
if instance.pk is None:
- raise ValueError("%r instance needs to have a primary key value before "
- "a many-to-many relationship can be used." %
- instance.__class__.__name__)
+ raise ValueError(
+ "%r instance needs to have a primary key value before "
+ "a many-to-many relationship can be used."
+ % instance.__class__.__name__
+ )
def __call__(self, *, manager):
manager = getattr(self.model, manager)
- manager_class = create_forward_many_to_many_manager(manager.__class__, rel, reverse)
+ manager_class = create_forward_many_to_many_manager(
+ manager.__class__, rel, reverse
+ )
return manager_class(instance=self.instance)
+
do_not_call_in_templates = True
def _build_remove_filters(self, removed_vals):
filters = Q((self.source_field_name, self.related_val))
# No need to add a subquery condition if removed_vals is a QuerySet without
# filters.
- removed_vals_filters = (not isinstance(removed_vals, QuerySet) or
- removed_vals._has_filters())
+ removed_vals_filters = (
+ not isinstance(removed_vals, QuerySet) or removed_vals._has_filters()
+ )
if removed_vals_filters:
- filters &= Q((f'{self.target_field_name}__in', removed_vals))
+ filters &= Q((f"{self.target_field_name}__in", removed_vals))
if self.symmetrical:
symmetrical_filters = Q((self.target_field_name, self.related_val))
if removed_vals_filters:
- symmetrical_filters &= Q((f'{self.source_field_name}__in', removed_vals))
+ symmetrical_filters &= Q(
+ (f"{self.source_field_name}__in", removed_vals)
+ )
filters |= symmetrical_filters
return filters
@@ -933,7 +1023,7 @@ def create_forward_many_to_many_manager(superclass, rel, reverse):
queryset._add_hints(instance=instances[0])
queryset = queryset.using(queryset._db or self._db)
- query = {'%s__in' % self.query_field_name: instances}
+ query = {"%s__in" % self.query_field_name: instances}
queryset = queryset._next_is_sticky().filter(**query)
# M2M: need to annotate the query in order to get the primary model
@@ -947,13 +1037,18 @@ def create_forward_many_to_many_manager(superclass, rel, reverse):
join_table = fk.model._meta.db_table
connection = connections[queryset.db]
qn = connection.ops.quote_name
- queryset = queryset.extra(select={
- '_prefetch_related_val_%s' % f.attname:
- '%s.%s' % (qn(join_table), qn(f.column)) for f in fk.local_related_fields})
+ queryset = queryset.extra(
+ select={
+ "_prefetch_related_val_%s"
+ % f.attname: "%s.%s"
+ % (qn(join_table), qn(f.column))
+ for f in fk.local_related_fields
+ }
+ )
return (
queryset,
lambda result: tuple(
- getattr(result, '_prefetch_related_val_%s' % f.attname)
+ getattr(result, "_prefetch_related_val_%s" % f.attname)
for f in fk.local_related_fields
),
lambda inst: tuple(
@@ -970,7 +1065,9 @@ def create_forward_many_to_many_manager(superclass, rel, reverse):
db = router.db_for_write(self.through, instance=self.instance)
with transaction.atomic(using=db, savepoint=False):
self._add_items(
- self.source_field_name, self.target_field_name, *objs,
+ self.source_field_name,
+ self.target_field_name,
+ *objs,
through_defaults=through_defaults,
)
# If this is a symmetrical m2m relation to self, add the mirror
@@ -982,30 +1079,41 @@ def create_forward_many_to_many_manager(superclass, rel, reverse):
*objs,
through_defaults=through_defaults,
)
+
add.alters_data = True
def remove(self, *objs):
self._remove_prefetched_objects()
self._remove_items(self.source_field_name, self.target_field_name, *objs)
+
remove.alters_data = True
def clear(self):
db = router.db_for_write(self.through, instance=self.instance)
with transaction.atomic(using=db, savepoint=False):
signals.m2m_changed.send(
- sender=self.through, action="pre_clear",
- instance=self.instance, reverse=self.reverse,
- model=self.model, pk_set=None, using=db,
+ sender=self.through,
+ action="pre_clear",
+ instance=self.instance,
+ reverse=self.reverse,
+ model=self.model,
+ pk_set=None,
+ using=db,
)
self._remove_prefetched_objects()
filters = self._build_remove_filters(super().get_queryset().using(db))
self.through._default_manager.using(db).filter(filters).delete()
signals.m2m_changed.send(
- sender=self.through, action="post_clear",
- instance=self.instance, reverse=self.reverse,
- model=self.model, pk_set=None, using=db,
+ sender=self.through,
+ action="post_clear",
+ instance=self.instance,
+ reverse=self.reverse,
+ model=self.model,
+ pk_set=None,
+ using=db,
)
+
clear.alters_data = True
def set(self, objs, *, clear=False, through_defaults=None):
@@ -1019,7 +1127,11 @@ def create_forward_many_to_many_manager(superclass, rel, reverse):
self.clear()
self.add(*objs, through_defaults=through_defaults)
else:
- old_ids = set(self.using(db).values_list(self.target_field.target_field.attname, flat=True))
+ old_ids = set(
+ self.using(db).values_list(
+ self.target_field.target_field.attname, flat=True
+ )
+ )
new_objs = []
for obj in objs:
@@ -1035,6 +1147,7 @@ def create_forward_many_to_many_manager(superclass, rel, reverse):
self.remove(*old_ids)
self.add(*new_objs, through_defaults=through_defaults)
+
set.alters_data = True
def create(self, *, through_defaults=None, **kwargs):
@@ -1042,26 +1155,33 @@ def create_forward_many_to_many_manager(superclass, rel, reverse):
new_obj = super(ManyRelatedManager, self.db_manager(db)).create(**kwargs)
self.add(new_obj, through_defaults=through_defaults)
return new_obj
+
create.alters_data = True
def get_or_create(self, *, through_defaults=None, **kwargs):
db = router.db_for_write(self.instance.__class__, instance=self.instance)
- obj, created = super(ManyRelatedManager, self.db_manager(db)).get_or_create(**kwargs)
+ obj, created = super(ManyRelatedManager, self.db_manager(db)).get_or_create(
+ **kwargs
+ )
# We only need to add() if created because if we got an object back
# from get() then the relationship already exists.
if created:
self.add(obj, through_defaults=through_defaults)
return obj, created
+
get_or_create.alters_data = True
def update_or_create(self, *, through_defaults=None, **kwargs):
db = router.db_for_write(self.instance.__class__, instance=self.instance)
- obj, created = super(ManyRelatedManager, self.db_manager(db)).update_or_create(**kwargs)
+ obj, created = super(
+ ManyRelatedManager, self.db_manager(db)
+ ).update_or_create(**kwargs)
# We only need to add() if created because if we got an object back
# from get() then the relationship already exists.
if created:
self.add(obj, through_defaults=through_defaults)
return obj, created
+
update_or_create.alters_data = True
def _get_target_ids(self, target_field_name, objs):
@@ -1069,6 +1189,7 @@ def create_forward_many_to_many_manager(superclass, rel, reverse):
Return the set of ids of `objs` that the target field references.
"""
from django.db.models import Model
+
target_ids = set()
target_field = self.through._meta.get_field(target_field_name)
for obj in objs:
@@ -1076,36 +1197,42 @@ def create_forward_many_to_many_manager(superclass, rel, reverse):
if not router.allow_relation(obj, self.instance):
raise ValueError(
'Cannot add "%r": instance is on database "%s", '
- 'value is on database "%s"' %
- (obj, self.instance._state.db, obj._state.db)
+ 'value is on database "%s"'
+ % (obj, self.instance._state.db, obj._state.db)
)
target_id = target_field.get_foreign_related_value(obj)[0]
if target_id is None:
raise ValueError(
- 'Cannot add "%r": the value for field "%s" is None' %
- (obj, target_field_name)
+ 'Cannot add "%r": the value for field "%s" is None'
+ % (obj, target_field_name)
)
target_ids.add(target_id)
elif isinstance(obj, Model):
raise TypeError(
- "'%s' instance expected, got %r" %
- (self.model._meta.object_name, obj)
+ "'%s' instance expected, got %r"
+ % (self.model._meta.object_name, obj)
)
else:
target_ids.add(target_field.get_prep_value(obj))
return target_ids
- def _get_missing_target_ids(self, source_field_name, target_field_name, db, target_ids):
+ def _get_missing_target_ids(
+ self, source_field_name, target_field_name, db, target_ids
+ ):
"""
Return the subset of ids of `objs` that aren't already assigned to
this relationship.
"""
- vals = self.through._default_manager.using(db).values_list(
- target_field_name, flat=True
- ).filter(**{
- source_field_name: self.related_val[0],
- '%s__in' % target_field_name: target_ids,
- })
+ vals = (
+ self.through._default_manager.using(db)
+ .values_list(target_field_name, flat=True)
+ .filter(
+ **{
+ source_field_name: self.related_val[0],
+ "%s__in" % target_field_name: target_ids,
+ }
+ )
+ )
return target_ids.difference(vals)
def _get_add_plan(self, db, source_field_name):
@@ -1123,21 +1250,27 @@ def create_forward_many_to_many_manager(superclass, rel, reverse):
# user-defined intermediary models as they could have other fields
# causing conflicts which must be surfaced.
can_ignore_conflicts = (
- self.through._meta.auto_created is not False and
- connections[db].features.supports_ignore_conflicts
+ self.through._meta.auto_created is not False
+ and connections[db].features.supports_ignore_conflicts
)
# Don't send the signal when inserting duplicate data row
# for symmetrical reverse entries.
- must_send_signals = (self.reverse or source_field_name == self.source_field_name) and (
- signals.m2m_changed.has_listeners(self.through)
- )
+ must_send_signals = (
+ self.reverse or source_field_name == self.source_field_name
+ ) and (signals.m2m_changed.has_listeners(self.through))
# Fast addition through bulk insertion can only be performed
# if no m2m_changed listeners are connected for self.through
# as they require the added set of ids to be provided via
# pk_set.
- return can_ignore_conflicts, must_send_signals, (can_ignore_conflicts and not must_send_signals)
+ return (
+ can_ignore_conflicts,
+ must_send_signals,
+ (can_ignore_conflicts and not must_send_signals),
+ )
- def _add_items(self, source_field_name, target_field_name, *objs, through_defaults=None):
+ def _add_items(
+ self, source_field_name, target_field_name, *objs, through_defaults=None
+ ):
# source_field_name: the PK fieldname in join table for the source object
# target_field_name: the PK fieldname in join table for the target object
# *objs - objects to add. Either object instances, or primary keys of object instances.
@@ -1147,15 +1280,22 @@ def create_forward_many_to_many_manager(superclass, rel, reverse):
through_defaults = dict(resolve_callables(through_defaults or {}))
target_ids = self._get_target_ids(target_field_name, objs)
db = router.db_for_write(self.through, instance=self.instance)
- can_ignore_conflicts, must_send_signals, can_fast_add = self._get_add_plan(db, source_field_name)
+ can_ignore_conflicts, must_send_signals, can_fast_add = self._get_add_plan(
+ db, source_field_name
+ )
if can_fast_add:
- self.through._default_manager.using(db).bulk_create([
- self.through(**{
- '%s_id' % source_field_name: self.related_val[0],
- '%s_id' % target_field_name: target_id,
- })
- for target_id in target_ids
- ], ignore_conflicts=True)
+ self.through._default_manager.using(db).bulk_create(
+ [
+ self.through(
+ **{
+ "%s_id" % source_field_name: self.related_val[0],
+ "%s_id" % target_field_name: target_id,
+ }
+ )
+ for target_id in target_ids
+ ],
+ ignore_conflicts=True,
+ )
return
missing_target_ids = self._get_missing_target_ids(
@@ -1164,24 +1304,38 @@ def create_forward_many_to_many_manager(superclass, rel, reverse):
with transaction.atomic(using=db, savepoint=False):
if must_send_signals:
signals.m2m_changed.send(
- sender=self.through, action='pre_add',
- instance=self.instance, reverse=self.reverse,
- model=self.model, pk_set=missing_target_ids, using=db,
+ sender=self.through,
+ action="pre_add",
+ instance=self.instance,
+ reverse=self.reverse,
+ model=self.model,
+ pk_set=missing_target_ids,
+ using=db,
)
# Add the ones that aren't there already.
- self.through._default_manager.using(db).bulk_create([
- self.through(**through_defaults, **{
- '%s_id' % source_field_name: self.related_val[0],
- '%s_id' % target_field_name: target_id,
- })
- for target_id in missing_target_ids
- ], ignore_conflicts=can_ignore_conflicts)
+ self.through._default_manager.using(db).bulk_create(
+ [
+ self.through(
+ **through_defaults,
+ **{
+ "%s_id" % source_field_name: self.related_val[0],
+ "%s_id" % target_field_name: target_id,
+ },
+ )
+ for target_id in missing_target_ids
+ ],
+ ignore_conflicts=can_ignore_conflicts,
+ )
if must_send_signals:
signals.m2m_changed.send(
- sender=self.through, action='post_add',
- instance=self.instance, reverse=self.reverse,
- model=self.model, pk_set=missing_target_ids, using=db,
+ sender=self.through,
+ action="post_add",
+ instance=self.instance,
+ reverse=self.reverse,
+ model=self.model,
+ pk_set=missing_target_ids,
+ using=db,
)
def _remove_items(self, source_field_name, target_field_name, *objs):
@@ -1205,23 +1359,32 @@ def create_forward_many_to_many_manager(superclass, rel, reverse):
with transaction.atomic(using=db, savepoint=False):
# Send a signal to the other end if need be.
signals.m2m_changed.send(
- sender=self.through, action="pre_remove",
- instance=self.instance, reverse=self.reverse,
- model=self.model, pk_set=old_ids, using=db,
+ sender=self.through,
+ action="pre_remove",
+ instance=self.instance,
+ reverse=self.reverse,
+ model=self.model,
+ pk_set=old_ids,
+ using=db,
)
target_model_qs = super().get_queryset()
if target_model_qs._has_filters():
- old_vals = target_model_qs.using(db).filter(**{
- '%s__in' % self.target_field.target_field.attname: old_ids})
+ old_vals = target_model_qs.using(db).filter(
+ **{"%s__in" % self.target_field.target_field.attname: old_ids}
+ )
else:
old_vals = old_ids
filters = self._build_remove_filters(old_vals)
self.through._default_manager.using(db).filter(filters).delete()
signals.m2m_changed.send(
- sender=self.through, action="post_remove",
- instance=self.instance, reverse=self.reverse,
- model=self.model, pk_set=old_ids, using=db,
+ sender=self.through,
+ action="post_remove",
+ instance=self.instance,
+ reverse=self.reverse,
+ model=self.model,
+ pk_set=old_ids,
+ using=db,
)
return ManyRelatedManager
diff --git a/django/db/models/fields/related_lookups.py b/django/db/models/fields/related_lookups.py
index fd97757b14..1bad1cf416 100644
--- a/django/db/models/fields/related_lookups.py
+++ b/django/db/models/fields/related_lookups.py
@@ -1,5 +1,10 @@
from django.db.models.lookups import (
- Exact, GreaterThan, GreaterThanOrEqual, In, IsNull, LessThan,
+ Exact,
+ GreaterThan,
+ GreaterThanOrEqual,
+ In,
+ IsNull,
+ LessThan,
LessThanOrEqual,
)
@@ -8,16 +13,21 @@ class MultiColSource:
contains_aggregate = False
def __init__(self, alias, targets, sources, field):
- self.targets, self.sources, self.field, self.alias = targets, sources, field, alias
+ self.targets, self.sources, self.field, self.alias = (
+ targets,
+ sources,
+ field,
+ alias,
+ )
self.output_field = self.field
def __repr__(self):
- return "{}({}, {})".format(
- self.__class__.__name__, self.alias, self.field)
+ return "{}({}, {})".format(self.__class__.__name__, self.alias, self.field)
def relabeled_clone(self, relabels):
- return self.__class__(relabels.get(self.alias, self.alias),
- self.targets, self.sources, self.field)
+ return self.__class__(
+ relabels.get(self.alias, self.alias), self.targets, self.sources, self.field
+ )
def get_lookup(self, lookup):
return self.output_field.get_lookup(lookup)
@@ -28,12 +38,15 @@ class MultiColSource:
def get_normalized_value(value, lhs):
from django.db.models import Model
+
if isinstance(value, Model):
value_list = []
sources = lhs.output_field.path_infos[-1].target_fields
for source in sources:
while not isinstance(value, source.model) and source.remote_field:
- source = source.remote_field.model._meta.get_field(source.remote_field.field_name)
+ source = source.remote_field.model._meta.get_field(
+ source.remote_field.field_name
+ )
try:
value_list.append(getattr(value, source.attname))
except AttributeError:
@@ -56,20 +69,21 @@ class RelatedIn(In):
# case ForeignKey to IntegerField given value 'abc'. The
# ForeignKey itself doesn't have validation for non-integers,
# so we must run validation using the target field.
- if hasattr(self.lhs.output_field, 'path_infos'):
+ if hasattr(self.lhs.output_field, "path_infos"):
# Run the target field's get_prep_value. We can safely
# assume there is only one as we don't get to the direct
# value branch otherwise.
- target_field = self.lhs.output_field.path_infos[-1].target_fields[-1]
+ target_field = self.lhs.output_field.path_infos[-1].target_fields[
+ -1
+ ]
self.rhs = [target_field.get_prep_value(v) for v in self.rhs]
- elif (
- not getattr(self.rhs, 'has_select_fields', True) and
- not getattr(self.lhs.field.target_field, 'primary_key', False)
+ elif not getattr(self.rhs, "has_select_fields", True) and not getattr(
+ self.lhs.field.target_field, "primary_key", False
):
self.rhs.clear_select_clause()
if (
- getattr(self.lhs.output_field, 'primary_key', False) and
- self.lhs.output_field.model == self.rhs.model
+ getattr(self.lhs.output_field, "primary_key", False)
+ and self.lhs.output_field.model == self.rhs.model
):
# A case like
# Restaurant.objects.filter(place__in=restaurant_qs), where
@@ -87,7 +101,10 @@ class RelatedIn(In):
# This clause is either a SubqueryConstraint (for values that need to be compiled to
# SQL) or an OR-combined list of (col1 = val1 AND col2 = val2 AND ...) clauses.
from django.db.models.sql.where import (
- AND, OR, SubqueryConstraint, WhereNode,
+ AND,
+ OR,
+ SubqueryConstraint,
+ WhereNode,
)
root_constraint = WhereNode(connector=OR)
@@ -95,31 +112,41 @@ class RelatedIn(In):
values = [get_normalized_value(value, self.lhs) for value in self.rhs]
for value in values:
value_constraint = WhereNode()
- for source, target, val in zip(self.lhs.sources, self.lhs.targets, value):
- lookup_class = target.get_lookup('exact')
- lookup = lookup_class(target.get_col(self.lhs.alias, source), val)
+ for source, target, val in zip(
+ self.lhs.sources, self.lhs.targets, value
+ ):
+ lookup_class = target.get_lookup("exact")
+ lookup = lookup_class(
+ target.get_col(self.lhs.alias, source), val
+ )
value_constraint.add(lookup, AND)
root_constraint.add(value_constraint, OR)
else:
root_constraint.add(
SubqueryConstraint(
- self.lhs.alias, [target.column for target in self.lhs.targets],
- [source.name for source in self.lhs.sources], self.rhs),
- AND)
+ self.lhs.alias,
+ [target.column for target in self.lhs.targets],
+ [source.name for source in self.lhs.sources],
+ self.rhs,
+ ),
+ AND,
+ )
return root_constraint.as_sql(compiler, connection)
return super().as_sql(compiler, connection)
class RelatedLookupMixin:
def get_prep_lookup(self):
- if not isinstance(self.lhs, MultiColSource) and not hasattr(self.rhs, 'resolve_expression'):
+ if not isinstance(self.lhs, MultiColSource) and not hasattr(
+ self.rhs, "resolve_expression"
+ ):
# If we get here, we are dealing with single-column relations.
self.rhs = get_normalized_value(self.rhs, self.lhs)[0]
# We need to run the related field's get_prep_value(). Consider case
# ForeignKey to IntegerField given value 'abc'. The ForeignKey itself
# doesn't have validation for non-integers, so we must run validation
# using the target field.
- if self.prepare_rhs and hasattr(self.lhs.output_field, 'path_infos'):
+ if self.prepare_rhs and hasattr(self.lhs.output_field, "path_infos"):
# Get the target field. We can safely assume there is only one
# as we don't get to the direct value branch otherwise.
target_field = self.lhs.output_field.path_infos[-1].target_fields[-1]
@@ -132,11 +159,15 @@ class RelatedLookupMixin:
assert self.rhs_is_direct_value()
self.rhs = get_normalized_value(self.rhs, self.lhs)
from django.db.models.sql.where import AND, WhereNode
+
root_constraint = WhereNode()
- for target, source, val in zip(self.lhs.targets, self.lhs.sources, self.rhs):
+ for target, source, val in zip(
+ self.lhs.targets, self.lhs.sources, self.rhs
+ ):
lookup_class = target.get_lookup(self.lookup_name)
root_constraint.add(
- lookup_class(target.get_col(self.lhs.alias, source), val), AND)
+ lookup_class(target.get_col(self.lhs.alias, source), val), AND
+ )
return root_constraint.as_sql(compiler, connection)
return super().as_sql(compiler, connection)
diff --git a/django/db/models/fields/reverse_related.py b/django/db/models/fields/reverse_related.py
index 6f0c788bbd..2ff66f34d0 100644
--- a/django/db/models/fields/reverse_related.py
+++ b/django/db/models/fields/reverse_related.py
@@ -36,8 +36,16 @@ class ForeignObjectRel(FieldCacheMixin):
null = True
empty_strings_allowed = False
- def __init__(self, field, to, related_name=None, related_query_name=None,
- limit_choices_to=None, parent_link=False, on_delete=None):
+ def __init__(
+ self,
+ field,
+ to,
+ related_name=None,
+ related_query_name=None,
+ limit_choices_to=None,
+ parent_link=False,
+ on_delete=None,
+ ):
self.field = field
self.model = to
self.related_name = related_name
@@ -73,14 +81,17 @@ class ForeignObjectRel(FieldCacheMixin):
"""
target_fields = self.path_infos[-1].target_fields
if len(target_fields) > 1:
- raise exceptions.FieldError("Can't use target_field for multicolumn relations.")
+ raise exceptions.FieldError(
+ "Can't use target_field for multicolumn relations."
+ )
return target_fields[0]
@cached_property
def related_model(self):
if not self.field.model:
raise AttributeError(
- "This property can't be accessed before self.field.contribute_to_class has been called.")
+ "This property can't be accessed before self.field.contribute_to_class has been called."
+ )
return self.field.model
@cached_property
@@ -110,7 +121,7 @@ class ForeignObjectRel(FieldCacheMixin):
return self.field.db_type
def __repr__(self):
- return '<%s: %s.%s>' % (
+ return "<%s: %s.%s>" % (
type(self).__name__,
self.related_model._meta.app_label,
self.related_model._meta.model_name,
@@ -147,12 +158,15 @@ class ForeignObjectRel(FieldCacheMixin):
# created and doesn't exist in the .models module.
# This is a reverse relation, so there is no reverse_path_infos to
# delete.
- state.pop('path_infos', None)
+ state.pop("path_infos", None)
return state
def get_choices(
- self, include_blank=True, blank_choice=BLANK_CHOICE_DASH,
- limit_choices_to=None, ordering=(),
+ self,
+ include_blank=True,
+ blank_choice=BLANK_CHOICE_DASH,
+ limit_choices_to=None,
+ ordering=(),
):
"""
Return choices with a default blank choices included, for use
@@ -165,13 +179,11 @@ class ForeignObjectRel(FieldCacheMixin):
qs = self.related_model._default_manager.complex_filter(limit_choices_to)
if ordering:
qs = qs.order_by(*ordering)
- return (blank_choice if include_blank else []) + [
- (x.pk, str(x)) for x in qs
- ]
+ return (blank_choice if include_blank else []) + [(x.pk, str(x)) for x in qs]
def is_hidden(self):
"""Should the related object be hidden?"""
- return bool(self.related_name) and self.related_name[-1] == '+'
+ return bool(self.related_name) and self.related_name[-1] == "+"
def get_joining_columns(self):
return self.field.get_reverse_joining_columns()
@@ -204,7 +216,7 @@ class ForeignObjectRel(FieldCacheMixin):
return None
if self.related_name:
return self.related_name
- return opts.model_name + ('_set' if self.multiple else '')
+ return opts.model_name + ("_set" if self.multiple else "")
def get_path_info(self, filtered_relation=None):
if filtered_relation:
@@ -239,10 +251,20 @@ class ManyToOneRel(ForeignObjectRel):
reverse relations into actual fields.
"""
- def __init__(self, field, to, field_name, related_name=None, related_query_name=None,
- limit_choices_to=None, parent_link=False, on_delete=None):
+ def __init__(
+ self,
+ field,
+ to,
+ field_name,
+ related_name=None,
+ related_query_name=None,
+ limit_choices_to=None,
+ parent_link=False,
+ on_delete=None,
+ ):
super().__init__(
- field, to,
+ field,
+ to,
related_name=related_name,
related_query_name=related_query_name,
limit_choices_to=limit_choices_to,
@@ -254,7 +276,7 @@ class ManyToOneRel(ForeignObjectRel):
def __getstate__(self):
state = super().__getstate__()
- state.pop('related_model', None)
+ state.pop("related_model", None)
return state
@property
@@ -267,7 +289,9 @@ class ManyToOneRel(ForeignObjectRel):
"""
field = self.model._meta.get_field(self.field_name)
if not field.concrete:
- raise exceptions.FieldDoesNotExist("No related field named '%s'" % self.field_name)
+ raise exceptions.FieldDoesNotExist(
+ "No related field named '%s'" % self.field_name
+ )
return field
def set_field_name(self):
@@ -282,10 +306,21 @@ class OneToOneRel(ManyToOneRel):
flags for the reverse relation.
"""
- def __init__(self, field, to, field_name, related_name=None, related_query_name=None,
- limit_choices_to=None, parent_link=False, on_delete=None):
+ def __init__(
+ self,
+ field,
+ to,
+ field_name,
+ related_name=None,
+ related_query_name=None,
+ limit_choices_to=None,
+ parent_link=False,
+ on_delete=None,
+ ):
super().__init__(
- field, to, field_name,
+ field,
+ to,
+ field_name,
related_name=related_name,
related_query_name=related_query_name,
limit_choices_to=limit_choices_to,
@@ -304,11 +339,21 @@ class ManyToManyRel(ForeignObjectRel):
flags for the reverse relation.
"""
- def __init__(self, field, to, related_name=None, related_query_name=None,
- limit_choices_to=None, symmetrical=True, through=None,
- through_fields=None, db_constraint=True):
+ def __init__(
+ self,
+ field,
+ to,
+ related_name=None,
+ related_query_name=None,
+ limit_choices_to=None,
+ symmetrical=True,
+ through=None,
+ through_fields=None,
+ db_constraint=True,
+ ):
super().__init__(
- field, to,
+ field,
+ to,
related_name=related_name,
related_query_name=related_query_name,
limit_choices_to=limit_choices_to,
@@ -343,7 +388,7 @@ class ManyToManyRel(ForeignObjectRel):
field = opts.get_field(self.through_fields[0])
else:
for field in opts.fields:
- rel = getattr(field, 'remote_field', None)
+ rel = getattr(field, "remote_field", None)
if rel and rel.model == self.model:
break
return field.foreign_related_fields[0]