Refs #33476 -- Refactored code to strictly match 88 characters line length.
This commit is contained in:
parent
9c19aff7c7
commit
7119f40c98
|
@ -224,9 +224,9 @@ class Apps:
|
||||||
and model.__module__ == app_models[model_name].__module__
|
and model.__module__ == app_models[model_name].__module__
|
||||||
):
|
):
|
||||||
warnings.warn(
|
warnings.warn(
|
||||||
"Model '%s.%s' was already registered. "
|
"Model '%s.%s' was already registered. Reloading models is not "
|
||||||
"Reloading models is not advised as it can lead to inconsistencies, "
|
"advised as it can lead to inconsistencies, most notably with "
|
||||||
"most notably with related models." % (app_label, model_name),
|
"related models." % (app_label, model_name),
|
||||||
RuntimeWarning,
|
RuntimeWarning,
|
||||||
stacklevel=2,
|
stacklevel=2,
|
||||||
)
|
)
|
||||||
|
|
|
@ -21,8 +21,8 @@ DEBUG = False
|
||||||
# on a live site.
|
# on a live site.
|
||||||
DEBUG_PROPAGATE_EXCEPTIONS = False
|
DEBUG_PROPAGATE_EXCEPTIONS = False
|
||||||
|
|
||||||
# People who get code error notifications.
|
# People who get code error notifications. In the format
|
||||||
# In the format [('Full Name', 'email@example.com'), ('Full Name', 'anotheremail@example.com')]
|
# [('Full Name', 'email@example.com'), ('Full Name', 'anotheremail@example.com')]
|
||||||
ADMINS = []
|
ADMINS = []
|
||||||
|
|
||||||
# List of IP addresses, as strings, that:
|
# List of IP addresses, as strings, that:
|
||||||
|
@ -319,7 +319,8 @@ DATA_UPLOAD_MAX_NUMBER_FIELDS = 1000
|
||||||
FILE_UPLOAD_TEMP_DIR = None
|
FILE_UPLOAD_TEMP_DIR = None
|
||||||
|
|
||||||
# The numeric mode to set newly-uploaded files to. The value should be a mode
|
# The numeric mode to set newly-uploaded files to. The value should be a mode
|
||||||
# you'd pass directly to os.chmod; see https://docs.python.org/library/os.html#files-and-directories.
|
# you'd pass directly to os.chmod; see
|
||||||
|
# https://docs.python.org/library/os.html#files-and-directories.
|
||||||
FILE_UPLOAD_PERMISSIONS = 0o644
|
FILE_UPLOAD_PERMISSIONS = 0o644
|
||||||
|
|
||||||
# The numeric mode to assign to newly-created directories, when uploading files.
|
# The numeric mode to assign to newly-created directories, when uploading files.
|
||||||
|
|
|
@ -447,9 +447,9 @@ class BaseModelAdminChecks:
|
||||||
):
|
):
|
||||||
return [
|
return [
|
||||||
checks.Error(
|
checks.Error(
|
||||||
"The value of '%s' cannot include the ManyToManyField '%s', "
|
"The value of '%s' cannot include the ManyToManyField "
|
||||||
"because that field manually specifies a relationship model."
|
"'%s', because that field manually specifies a "
|
||||||
% (label, field_name),
|
"relationship model." % (label, field_name),
|
||||||
obj=obj.__class__,
|
obj=obj.__class__,
|
||||||
id="admin.E013",
|
id="admin.E013",
|
||||||
)
|
)
|
||||||
|
@ -568,8 +568,8 @@ class BaseModelAdminChecks:
|
||||||
return [
|
return [
|
||||||
checks.Error(
|
checks.Error(
|
||||||
"The value of '%s' refers to '%s', which is not an "
|
"The value of '%s' refers to '%s', which is not an "
|
||||||
"instance of ForeignKey, and does not have a 'choices' definition."
|
"instance of ForeignKey, and does not have a 'choices' "
|
||||||
% (label, field_name),
|
"definition." % (label, field_name),
|
||||||
obj=obj.__class__,
|
obj=obj.__class__,
|
||||||
id="admin.E023",
|
id="admin.E023",
|
||||||
)
|
)
|
||||||
|
@ -585,8 +585,8 @@ class BaseModelAdminChecks:
|
||||||
if val not in (HORIZONTAL, VERTICAL):
|
if val not in (HORIZONTAL, VERTICAL):
|
||||||
return [
|
return [
|
||||||
checks.Error(
|
checks.Error(
|
||||||
"The value of '%s' must be either admin.HORIZONTAL or admin.VERTICAL."
|
"The value of '%s' must be either admin.HORIZONTAL or "
|
||||||
% label,
|
"admin.VERTICAL." % label,
|
||||||
obj=obj.__class__,
|
obj=obj.__class__,
|
||||||
id="admin.E024",
|
id="admin.E024",
|
||||||
)
|
)
|
||||||
|
@ -598,7 +598,8 @@ class BaseModelAdminChecks:
|
||||||
if not callable(obj.view_on_site) and not isinstance(obj.view_on_site, bool):
|
if not callable(obj.view_on_site) and not isinstance(obj.view_on_site, bool):
|
||||||
return [
|
return [
|
||||||
checks.Error(
|
checks.Error(
|
||||||
"The value of 'view_on_site' must be a callable or a boolean value.",
|
"The value of 'view_on_site' must be a callable or a boolean "
|
||||||
|
"value.",
|
||||||
obj=obj.__class__,
|
obj=obj.__class__,
|
||||||
id="admin.E025",
|
id="admin.E025",
|
||||||
)
|
)
|
||||||
|
@ -643,9 +644,9 @@ class BaseModelAdminChecks:
|
||||||
):
|
):
|
||||||
return [
|
return [
|
||||||
checks.Error(
|
checks.Error(
|
||||||
"The value of '%s' refers to '%s', which must not be a DateTimeField, "
|
"The value of '%s' refers to '%s', which must not be a "
|
||||||
"a ForeignKey, a OneToOneField, or a ManyToManyField."
|
"DateTimeField, a ForeignKey, a OneToOneField, or a "
|
||||||
% (label, field_name),
|
"ManyToManyField." % (label, field_name),
|
||||||
obj=obj.__class__,
|
obj=obj.__class__,
|
||||||
id="admin.E028",
|
id="admin.E028",
|
||||||
)
|
)
|
||||||
|
@ -955,8 +956,8 @@ class ModelAdminChecks(BaseModelAdminChecks):
|
||||||
if field_name not in obj.list_display:
|
if field_name not in obj.list_display:
|
||||||
return [
|
return [
|
||||||
checks.Error(
|
checks.Error(
|
||||||
"The value of '%s' refers to '%s', which is not defined in 'list_display'."
|
"The value of '%s' refers to '%s', which is not defined in "
|
||||||
% (label, field_name),
|
"'list_display'." % (label, field_name),
|
||||||
obj=obj.__class__,
|
obj=obj.__class__,
|
||||||
id="admin.E111",
|
id="admin.E111",
|
||||||
)
|
)
|
||||||
|
@ -1027,8 +1028,8 @@ class ModelAdminChecks(BaseModelAdminChecks):
|
||||||
except (NotRelationField, FieldDoesNotExist):
|
except (NotRelationField, FieldDoesNotExist):
|
||||||
return [
|
return [
|
||||||
checks.Error(
|
checks.Error(
|
||||||
"The value of '%s' refers to '%s', which does not refer to a Field."
|
"The value of '%s' refers to '%s', which does not refer to a "
|
||||||
% (label, field),
|
"Field." % (label, field),
|
||||||
obj=obj.__class__,
|
obj=obj.__class__,
|
||||||
id="admin.E116",
|
id="admin.E116",
|
||||||
)
|
)
|
||||||
|
@ -1107,8 +1108,8 @@ class ModelAdminChecks(BaseModelAdminChecks):
|
||||||
elif obj.list_display_links and field_name in obj.list_display_links:
|
elif obj.list_display_links and field_name in obj.list_display_links:
|
||||||
return [
|
return [
|
||||||
checks.Error(
|
checks.Error(
|
||||||
"The value of '%s' cannot be in both 'list_editable' and 'list_display_links'."
|
"The value of '%s' cannot be in both 'list_editable' and "
|
||||||
% field_name,
|
"'list_display_links'." % field_name,
|
||||||
obj=obj.__class__,
|
obj=obj.__class__,
|
||||||
id="admin.E123",
|
id="admin.E123",
|
||||||
)
|
)
|
||||||
|
@ -1122,9 +1123,9 @@ class ModelAdminChecks(BaseModelAdminChecks):
|
||||||
):
|
):
|
||||||
return [
|
return [
|
||||||
checks.Error(
|
checks.Error(
|
||||||
"The value of '%s' refers to the first field in 'list_display' ('%s'), "
|
"The value of '%s' refers to the first field in 'list_display' "
|
||||||
"which cannot be used unless 'list_display_links' is set."
|
"('%s'), which cannot be used unless 'list_display_links' is "
|
||||||
% (label, obj.list_display[0]),
|
"set." % (label, obj.list_display[0]),
|
||||||
obj=obj.__class__,
|
obj=obj.__class__,
|
||||||
id="admin.E124",
|
id="admin.E124",
|
||||||
)
|
)
|
||||||
|
@ -1132,8 +1133,8 @@ class ModelAdminChecks(BaseModelAdminChecks):
|
||||||
elif not field.editable:
|
elif not field.editable:
|
||||||
return [
|
return [
|
||||||
checks.Error(
|
checks.Error(
|
||||||
"The value of '%s' refers to '%s', which is not editable through the admin."
|
"The value of '%s' refers to '%s', which is not editable "
|
||||||
% (label, field_name),
|
"through the admin." % (label, field_name),
|
||||||
obj=obj.__class__,
|
obj=obj.__class__,
|
||||||
id="admin.E125",
|
id="admin.E125",
|
||||||
)
|
)
|
||||||
|
|
|
@ -64,7 +64,8 @@ class LogEntry(models.Model):
|
||||||
null=True,
|
null=True,
|
||||||
)
|
)
|
||||||
object_id = models.TextField(_("object id"), blank=True, null=True)
|
object_id = models.TextField(_("object id"), blank=True, null=True)
|
||||||
# Translators: 'repr' means representation (https://docs.python.org/library/functions.html#repr)
|
# Translators: 'repr' means representation
|
||||||
|
# (https://docs.python.org/library/functions.html#repr)
|
||||||
object_repr = models.CharField(_("object repr"), max_length=200)
|
object_repr = models.CharField(_("object repr"), max_length=200)
|
||||||
action_flag = models.PositiveSmallIntegerField(
|
action_flag = models.PositiveSmallIntegerField(
|
||||||
_("action flag"), choices=ACTION_FLAG_CHOICES
|
_("action flag"), choices=ACTION_FLAG_CHOICES
|
||||||
|
|
|
@ -1276,7 +1276,9 @@ class ModelAdmin(BaseModelAdmin):
|
||||||
"has_add_permission": self.has_add_permission(request),
|
"has_add_permission": self.has_add_permission(request),
|
||||||
"has_change_permission": self.has_change_permission(request, obj),
|
"has_change_permission": self.has_change_permission(request, obj),
|
||||||
"has_delete_permission": self.has_delete_permission(request, obj),
|
"has_delete_permission": self.has_delete_permission(request, obj),
|
||||||
"has_editable_inline_admin_formsets": has_editable_inline_admin_formsets,
|
"has_editable_inline_admin_formsets": (
|
||||||
|
has_editable_inline_admin_formsets
|
||||||
|
),
|
||||||
"has_file_field": context["adminform"].form.is_multipart()
|
"has_file_field": context["adminform"].form.is_multipart()
|
||||||
or any(
|
or any(
|
||||||
admin_formset.formset.is_multipart()
|
admin_formset.formset.is_multipart()
|
||||||
|
@ -1383,7 +1385,8 @@ class ModelAdmin(BaseModelAdmin):
|
||||||
elif "_addanother" in request.POST:
|
elif "_addanother" in request.POST:
|
||||||
msg = format_html(
|
msg = format_html(
|
||||||
_(
|
_(
|
||||||
"The {name} “{obj}” was added successfully. You may add another {name} below."
|
"The {name} “{obj}” was added successfully. You may add another "
|
||||||
|
"{name} below."
|
||||||
),
|
),
|
||||||
**msg_dict,
|
**msg_dict,
|
||||||
)
|
)
|
||||||
|
@ -1444,7 +1447,8 @@ class ModelAdmin(BaseModelAdmin):
|
||||||
if "_continue" in request.POST:
|
if "_continue" in request.POST:
|
||||||
msg = format_html(
|
msg = format_html(
|
||||||
_(
|
_(
|
||||||
"The {name} “{obj}” was changed successfully. You may edit it again below."
|
"The {name} “{obj}” was changed successfully. You may edit it "
|
||||||
|
"again below."
|
||||||
),
|
),
|
||||||
**msg_dict,
|
**msg_dict,
|
||||||
)
|
)
|
||||||
|
@ -1458,7 +1462,8 @@ class ModelAdmin(BaseModelAdmin):
|
||||||
elif "_saveasnew" in request.POST:
|
elif "_saveasnew" in request.POST:
|
||||||
msg = format_html(
|
msg = format_html(
|
||||||
_(
|
_(
|
||||||
"The {name} “{obj}” was added successfully. You may edit it again below."
|
"The {name} “{obj}” was added successfully. You may edit it again "
|
||||||
|
"below."
|
||||||
),
|
),
|
||||||
**msg_dict,
|
**msg_dict,
|
||||||
)
|
)
|
||||||
|
@ -1476,7 +1481,8 @@ class ModelAdmin(BaseModelAdmin):
|
||||||
elif "_addanother" in request.POST:
|
elif "_addanother" in request.POST:
|
||||||
msg = format_html(
|
msg = format_html(
|
||||||
_(
|
_(
|
||||||
"The {name} “{obj}” was changed successfully. You may add another {name} below."
|
"The {name} “{obj}” was changed successfully. You may add another "
|
||||||
|
"{name} below."
|
||||||
),
|
),
|
||||||
**msg_dict,
|
**msg_dict,
|
||||||
)
|
)
|
||||||
|
@ -2389,8 +2395,9 @@ class InlineModelAdmin(BaseModelAdmin):
|
||||||
objs = []
|
objs = []
|
||||||
for p in collector.protected:
|
for p in collector.protected:
|
||||||
objs.append(
|
objs.append(
|
||||||
# Translators: Model verbose name and instance representation,
|
# Translators: Model verbose name and instance
|
||||||
# suitable to be an item in a list.
|
# representation, suitable to be an item in a
|
||||||
|
# list.
|
||||||
_("%(class_name)s %(instance)s")
|
_("%(class_name)s %(instance)s")
|
||||||
% {"class_name": p._meta.verbose_name, "instance": p}
|
% {"class_name": p._meta.verbose_name, "instance": p}
|
||||||
)
|
)
|
||||||
|
|
|
@ -32,7 +32,7 @@ def get_admin_log(parser, token):
|
||||||
|
|
||||||
Usage::
|
Usage::
|
||||||
|
|
||||||
{% get_admin_log [limit] as [varname] for_user [context_var_containing_user_obj] %}
|
{% get_admin_log [limit] as [varname] for_user [context_var_with_user_obj] %}
|
||||||
|
|
||||||
Examples::
|
Examples::
|
||||||
|
|
||||||
|
|
|
@ -70,12 +70,14 @@ def authenticate(request=None, **credentials):
|
||||||
try:
|
try:
|
||||||
backend_signature.bind(request, **credentials)
|
backend_signature.bind(request, **credentials)
|
||||||
except TypeError:
|
except TypeError:
|
||||||
# This backend doesn't accept these credentials as arguments. Try the next one.
|
# This backend doesn't accept these credentials as arguments. Try
|
||||||
|
# the next one.
|
||||||
continue
|
continue
|
||||||
try:
|
try:
|
||||||
user = backend.authenticate(request, **credentials)
|
user = backend.authenticate(request, **credentials)
|
||||||
except PermissionDenied:
|
except PermissionDenied:
|
||||||
# This backend says to stop in our tracks - this user should not be allowed in at all.
|
# This backend says to stop in our tracks - this user should not be
|
||||||
|
# allowed in at all.
|
||||||
break
|
break
|
||||||
if user is None:
|
if user is None:
|
||||||
continue
|
continue
|
||||||
|
|
|
@ -61,8 +61,8 @@ def check_user_model(app_configs=None, **kwargs):
|
||||||
]:
|
]:
|
||||||
errors.append(
|
errors.append(
|
||||||
checks.Error(
|
checks.Error(
|
||||||
"'%s.%s' must be unique because it is named as the 'USERNAME_FIELD'."
|
"'%s.%s' must be unique because it is named as the "
|
||||||
% (cls._meta.object_name, cls.USERNAME_FIELD),
|
"'USERNAME_FIELD'." % (cls._meta.object_name, cls.USERNAME_FIELD),
|
||||||
obj=cls,
|
obj=cls,
|
||||||
id="auth.E003",
|
id="auth.E003",
|
||||||
)
|
)
|
||||||
|
@ -72,7 +72,10 @@ def check_user_model(app_configs=None, **kwargs):
|
||||||
checks.Warning(
|
checks.Warning(
|
||||||
"'%s.%s' is named as the 'USERNAME_FIELD', but it is not unique."
|
"'%s.%s' is named as the 'USERNAME_FIELD', but it is not unique."
|
||||||
% (cls._meta.object_name, cls.USERNAME_FIELD),
|
% (cls._meta.object_name, cls.USERNAME_FIELD),
|
||||||
hint="Ensure that your authentication backend(s) can handle non-unique usernames.",
|
hint=(
|
||||||
|
"Ensure that your authentication backend(s) can handle "
|
||||||
|
"non-unique usernames."
|
||||||
|
),
|
||||||
obj=cls,
|
obj=cls,
|
||||||
id="auth.W004",
|
id="auth.W004",
|
||||||
)
|
)
|
||||||
|
@ -197,8 +200,8 @@ def check_models_permissions(app_configs=None, **kwargs):
|
||||||
if codename in builtin_permissions:
|
if codename in builtin_permissions:
|
||||||
errors.append(
|
errors.append(
|
||||||
checks.Error(
|
checks.Error(
|
||||||
"The permission codenamed '%s' clashes with a builtin permission "
|
"The permission codenamed '%s' clashes with a builtin "
|
||||||
"for model '%s'." % (codename, opts.label),
|
"permission for model '%s'." % (codename, opts.label),
|
||||||
obj=model,
|
obj=model,
|
||||||
id="auth.E005",
|
id="auth.E005",
|
||||||
)
|
)
|
||||||
|
|
|
@ -24,7 +24,10 @@ class Command(BaseCommand):
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"username",
|
"username",
|
||||||
nargs="?",
|
nargs="?",
|
||||||
help="Username to change password for; by default, it's the current username.",
|
help=(
|
||||||
|
"Username to change password for; by default, it's the current "
|
||||||
|
"username."
|
||||||
|
),
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--database",
|
"--database",
|
||||||
|
|
|
@ -102,14 +102,20 @@ class Migration(migrations.Migration):
|
||||||
"is_superuser",
|
"is_superuser",
|
||||||
models.BooleanField(
|
models.BooleanField(
|
||||||
default=False,
|
default=False,
|
||||||
help_text="Designates that this user has all permissions without explicitly assigning them.",
|
help_text=(
|
||||||
|
"Designates that this user has all permissions without "
|
||||||
|
"explicitly assigning them."
|
||||||
|
),
|
||||||
verbose_name="superuser status",
|
verbose_name="superuser status",
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"username",
|
"username",
|
||||||
models.CharField(
|
models.CharField(
|
||||||
help_text="Required. 30 characters or fewer. Letters, digits and @/./+/-/_ only.",
|
help_text=(
|
||||||
|
"Required. 30 characters or fewer. Letters, digits and "
|
||||||
|
"@/./+/-/_ only."
|
||||||
|
),
|
||||||
unique=True,
|
unique=True,
|
||||||
max_length=30,
|
max_length=30,
|
||||||
verbose_name="username",
|
verbose_name="username",
|
||||||
|
@ -138,7 +144,9 @@ class Migration(migrations.Migration):
|
||||||
"is_staff",
|
"is_staff",
|
||||||
models.BooleanField(
|
models.BooleanField(
|
||||||
default=False,
|
default=False,
|
||||||
help_text="Designates whether the user can log into this admin site.",
|
help_text=(
|
||||||
|
"Designates whether the user can log into this admin site."
|
||||||
|
),
|
||||||
verbose_name="staff status",
|
verbose_name="staff status",
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -148,8 +156,8 @@ class Migration(migrations.Migration):
|
||||||
default=True,
|
default=True,
|
||||||
verbose_name="active",
|
verbose_name="active",
|
||||||
help_text=(
|
help_text=(
|
||||||
"Designates whether this user should be treated as active. Unselect this instead of deleting "
|
"Designates whether this user should be treated as active. "
|
||||||
"accounts."
|
"Unselect this instead of deleting accounts."
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -168,8 +176,8 @@ class Migration(migrations.Migration):
|
||||||
related_name="user_set",
|
related_name="user_set",
|
||||||
related_query_name="user",
|
related_query_name="user",
|
||||||
help_text=(
|
help_text=(
|
||||||
"The groups this user belongs to. A user will get all permissions granted to each of their "
|
"The groups this user belongs to. A user will get all "
|
||||||
"groups."
|
"permissions granted to each of their groups."
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -17,7 +17,10 @@ class Migration(migrations.Migration):
|
||||||
error_messages={"unique": "A user with that username already exists."},
|
error_messages={"unique": "A user with that username already exists."},
|
||||||
max_length=30,
|
max_length=30,
|
||||||
validators=[validators.UnicodeUsernameValidator()],
|
validators=[validators.UnicodeUsernameValidator()],
|
||||||
help_text="Required. 30 characters or fewer. Letters, digits and @/./+/-/_ only.",
|
help_text=(
|
||||||
|
"Required. 30 characters or fewer. Letters, digits and @/./+/-/_ "
|
||||||
|
"only."
|
||||||
|
),
|
||||||
unique=True,
|
unique=True,
|
||||||
verbose_name="username",
|
verbose_name="username",
|
||||||
),
|
),
|
||||||
|
|
|
@ -14,7 +14,10 @@ class Migration(migrations.Migration):
|
||||||
name="username",
|
name="username",
|
||||||
field=models.CharField(
|
field=models.CharField(
|
||||||
error_messages={"unique": "A user with that username already exists."},
|
error_messages={"unique": "A user with that username already exists."},
|
||||||
help_text="Required. 30 characters or fewer. Letters, digits and @/./+/-/_ only.",
|
help_text=(
|
||||||
|
"Required. 30 characters or fewer. Letters, digits and @/./+/-/_ "
|
||||||
|
"only."
|
||||||
|
),
|
||||||
max_length=30,
|
max_length=30,
|
||||||
unique=True,
|
unique=True,
|
||||||
validators=[validators.UnicodeUsernameValidator()],
|
validators=[validators.UnicodeUsernameValidator()],
|
||||||
|
|
|
@ -14,7 +14,10 @@ class Migration(migrations.Migration):
|
||||||
name="username",
|
name="username",
|
||||||
field=models.CharField(
|
field=models.CharField(
|
||||||
error_messages={"unique": "A user with that username already exists."},
|
error_messages={"unique": "A user with that username already exists."},
|
||||||
help_text="Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.",
|
help_text=(
|
||||||
|
"Required. 150 characters or fewer. Letters, digits and @/./+/-/_ "
|
||||||
|
"only."
|
||||||
|
),
|
||||||
max_length=150,
|
max_length=150,
|
||||||
unique=True,
|
unique=True,
|
||||||
validators=[validators.UnicodeUsernameValidator()],
|
validators=[validators.UnicodeUsernameValidator()],
|
||||||
|
|
|
@ -25,8 +25,9 @@ class AccessMixin:
|
||||||
login_url = self.login_url or settings.LOGIN_URL
|
login_url = self.login_url or settings.LOGIN_URL
|
||||||
if not login_url:
|
if not login_url:
|
||||||
raise ImproperlyConfigured(
|
raise ImproperlyConfigured(
|
||||||
"{0} is missing the login_url attribute. Define {0}.login_url, settings.LOGIN_URL, or override "
|
f"{self.__class__.__name__} is missing the login_url attribute. Define "
|
||||||
"{0}.get_login_url().".format(self.__class__.__name__)
|
f"{self.__class__.__name__}.login_url, settings.LOGIN_URL, or override "
|
||||||
|
f"{self.__class__.__name__}.get_login_url()."
|
||||||
)
|
)
|
||||||
return str(login_url)
|
return str(login_url)
|
||||||
|
|
||||||
|
@ -84,8 +85,10 @@ class PermissionRequiredMixin(AccessMixin):
|
||||||
"""
|
"""
|
||||||
if self.permission_required is None:
|
if self.permission_required is None:
|
||||||
raise ImproperlyConfigured(
|
raise ImproperlyConfigured(
|
||||||
"{0} is missing the permission_required attribute. Define {0}.permission_required, or override "
|
f"{self.__class__.__name__} is missing the "
|
||||||
"{0}.get_permission_required().".format(self.__class__.__name__)
|
f"permission_required attribute. Define "
|
||||||
|
f"{self.__class__.__name__}.permission_required, or override "
|
||||||
|
f"{self.__class__.__name__}.get_permission_required()."
|
||||||
)
|
)
|
||||||
if isinstance(self.permission_required, str):
|
if isinstance(self.permission_required, str):
|
||||||
perms = (self.permission_required,)
|
perms = (self.permission_required,)
|
||||||
|
|
|
@ -435,7 +435,8 @@ class AnonymousUser:
|
||||||
|
|
||||||
def __int__(self):
|
def __int__(self):
|
||||||
raise TypeError(
|
raise TypeError(
|
||||||
"Cannot cast AnonymousUser to int. Are you trying to use it in place of User?"
|
"Cannot cast AnonymousUser to int. Are you trying to use it in place of "
|
||||||
|
"User?"
|
||||||
)
|
)
|
||||||
|
|
||||||
def save(self):
|
def save(self):
|
||||||
|
|
|
@ -28,7 +28,10 @@ def get_password_validators(validator_config):
|
||||||
try:
|
try:
|
||||||
klass = import_string(validator["NAME"])
|
klass = import_string(validator["NAME"])
|
||||||
except ImportError:
|
except ImportError:
|
||||||
msg = "The module in NAME could not be imported: %s. Check your AUTH_PASSWORD_VALIDATORS setting."
|
msg = (
|
||||||
|
"The module in NAME could not be imported: %s. Check your "
|
||||||
|
"AUTH_PASSWORD_VALIDATORS setting."
|
||||||
|
)
|
||||||
raise ImproperlyConfigured(msg % validator["NAME"])
|
raise ImproperlyConfigured(msg % validator["NAME"])
|
||||||
validators.append(klass(**validator.get("OPTIONS", {})))
|
validators.append(klass(**validator.get("OPTIONS", {})))
|
||||||
|
|
||||||
|
@ -105,8 +108,10 @@ class MinimumLengthValidator:
|
||||||
if len(password) < self.min_length:
|
if len(password) < self.min_length:
|
||||||
raise ValidationError(
|
raise ValidationError(
|
||||||
ngettext(
|
ngettext(
|
||||||
"This password is too short. It must contain at least %(min_length)d character.",
|
"This password is too short. It must contain at least "
|
||||||
"This password is too short. It must contain at least %(min_length)d characters.",
|
"%(min_length)d character.",
|
||||||
|
"This password is too short. It must contain at least "
|
||||||
|
"%(min_length)d characters.",
|
||||||
self.min_length,
|
self.min_length,
|
||||||
),
|
),
|
||||||
code="password_too_short",
|
code="password_too_short",
|
||||||
|
|
|
@ -19,8 +19,8 @@ class GenericInlineModelAdminChecks(InlineModelAdminChecks):
|
||||||
return []
|
return []
|
||||||
|
|
||||||
def _check_relation(self, obj, parent_model):
|
def _check_relation(self, obj, parent_model):
|
||||||
# There's no FK, but we do need to confirm that the ct_field and ct_fk_field are valid,
|
# There's no FK, but we do need to confirm that the ct_field and
|
||||||
# and that they are part of a GenericForeignKey.
|
# ct_fk_field are valid, and that they are part of a GenericForeignKey.
|
||||||
|
|
||||||
gfks = [
|
gfks = [
|
||||||
f
|
f
|
||||||
|
@ -75,7 +75,8 @@ class GenericInlineModelAdminChecks(InlineModelAdminChecks):
|
||||||
|
|
||||||
return [
|
return [
|
||||||
checks.Error(
|
checks.Error(
|
||||||
"'%s' has no GenericForeignKey using content type field '%s' and object ID field '%s'."
|
"'%s' has no GenericForeignKey using content type field '%s' and "
|
||||||
|
"object ID field '%s'."
|
||||||
% (
|
% (
|
||||||
obj.model._meta.label,
|
obj.model._meta.label,
|
||||||
obj.ct_field,
|
obj.ct_field,
|
||||||
|
|
|
@ -120,8 +120,9 @@ class ContentTypeManager(models.Manager):
|
||||||
|
|
||||||
def _add_to_cache(self, using, ct):
|
def _add_to_cache(self, using, ct):
|
||||||
"""Insert a ContentType into the cache."""
|
"""Insert a ContentType into the cache."""
|
||||||
# Note it's possible for ContentType objects to be stale; model_class() will return None.
|
# Note it's possible for ContentType objects to be stale; model_class()
|
||||||
# Hence, there is no reliance on model._meta.app_label here, just using the model fields instead.
|
# will return None. Hence, there is no reliance on
|
||||||
|
# model._meta.app_label here, just using the model fields instead.
|
||||||
key = (ct.app_label, ct.model)
|
key = (ct.app_label, ct.model)
|
||||||
self._cache.setdefault(using, {})[key] = ct
|
self._cache.setdefault(using, {})[key] = ct
|
||||||
self._cache.setdefault(using, {})[ct.id] = ct
|
self._cache.setdefault(using, {})[ct.id] = ct
|
||||||
|
|
|
@ -12,7 +12,8 @@ class FlatpageForm(forms.ModelForm):
|
||||||
max_length=100,
|
max_length=100,
|
||||||
regex=r"^[-\w/\.~]+$",
|
regex=r"^[-\w/\.~]+$",
|
||||||
help_text=_(
|
help_text=_(
|
||||||
"Example: “/about/contact/”. Make sure to have leading and trailing slashes."
|
"Example: “/about/contact/”. Make sure to have leading and trailing "
|
||||||
|
"slashes."
|
||||||
),
|
),
|
||||||
error_messages={
|
error_messages={
|
||||||
"invalid": _(
|
"invalid": _(
|
||||||
|
|
|
@ -34,8 +34,8 @@ class Migration(migrations.Migration):
|
||||||
"template_name",
|
"template_name",
|
||||||
models.CharField(
|
models.CharField(
|
||||||
help_text=(
|
help_text=(
|
||||||
"Example: “flatpages/contact_page.html”. If this isn’t provided, the system will use "
|
"Example: “flatpages/contact_page.html”. If this isn’t "
|
||||||
"“flatpages/default.html”."
|
"provided, the system will use “flatpages/default.html”."
|
||||||
),
|
),
|
||||||
max_length=70,
|
max_length=70,
|
||||||
verbose_name="template name",
|
verbose_name="template name",
|
||||||
|
@ -46,7 +46,10 @@ class Migration(migrations.Migration):
|
||||||
"registration_required",
|
"registration_required",
|
||||||
models.BooleanField(
|
models.BooleanField(
|
||||||
default=False,
|
default=False,
|
||||||
help_text="If this is checked, only logged-in users will be able to view the page.",
|
help_text=(
|
||||||
|
"If this is checked, only logged-in users will be able to "
|
||||||
|
"view the page."
|
||||||
|
),
|
||||||
verbose_name="registration required",
|
verbose_name="registration required",
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -158,12 +158,14 @@ class BaseSpatialOperations:
|
||||||
# Routines for getting the OGC-compliant models.
|
# Routines for getting the OGC-compliant models.
|
||||||
def geometry_columns(self):
|
def geometry_columns(self):
|
||||||
raise NotImplementedError(
|
raise NotImplementedError(
|
||||||
"Subclasses of BaseSpatialOperations must provide a geometry_columns() method."
|
"Subclasses of BaseSpatialOperations must provide a geometry_columns() "
|
||||||
|
"method."
|
||||||
)
|
)
|
||||||
|
|
||||||
def spatial_ref_sys(self):
|
def spatial_ref_sys(self):
|
||||||
raise NotImplementedError(
|
raise NotImplementedError(
|
||||||
"subclasses of BaseSpatialOperations must a provide spatial_ref_sys() method"
|
"subclasses of BaseSpatialOperations must a provide spatial_ref_sys() "
|
||||||
|
"method"
|
||||||
)
|
)
|
||||||
|
|
||||||
distance_expr_for_lookup = staticmethod(Distance)
|
distance_expr_for_lookup = staticmethod(Distance)
|
||||||
|
|
|
@ -20,7 +20,8 @@ class DatabaseFeatures(BaseSpatialFeatures, OracleDatabaseFeatures):
|
||||||
skips.update(
|
skips.update(
|
||||||
{
|
{
|
||||||
"Oracle doesn't support spatial operators in constraints.": {
|
"Oracle doesn't support spatial operators in constraints.": {
|
||||||
"gis_tests.gis_migrations.test_operations.OperationTests.test_add_check_constraint",
|
"gis_tests.gis_migrations.test_operations.OperationTests."
|
||||||
|
"test_add_check_constraint",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
@ -40,7 +40,10 @@ class SDORelate(SpatialOperator):
|
||||||
sql_template = "SDO_RELATE(%(lhs)s, %(rhs)s, 'mask=%(mask)s') = 'TRUE'"
|
sql_template = "SDO_RELATE(%(lhs)s, %(rhs)s, 'mask=%(mask)s') = 'TRUE'"
|
||||||
|
|
||||||
def check_relate_argument(self, arg):
|
def check_relate_argument(self, arg):
|
||||||
masks = "TOUCH|OVERLAPBDYDISJOINT|OVERLAPBDYINTERSECT|EQUAL|INSIDE|COVEREDBY|CONTAINS|COVERS|ANYINTERACT|ON"
|
masks = (
|
||||||
|
"TOUCH|OVERLAPBDYDISJOINT|OVERLAPBDYINTERSECT|EQUAL|INSIDE|COVEREDBY|"
|
||||||
|
"CONTAINS|COVERS|ANYINTERACT|ON"
|
||||||
|
)
|
||||||
mask_regex = re.compile(r"^(%s)(\+(%s))*$" % (masks, masks), re.I)
|
mask_regex = re.compile(r"^(%s)(\+(%s))*$" % (masks, masks), re.I)
|
||||||
if not isinstance(arg, str) or not mask_regex.match(arg):
|
if not isinstance(arg, str) or not mask_regex.match(arg):
|
||||||
raise ValueError('Invalid SDO_RELATE mask: "%s"' % arg)
|
raise ValueError('Invalid SDO_RELATE mask: "%s"' % arg)
|
||||||
|
@ -105,7 +108,8 @@ class OracleOperations(BaseSpatialOperations, DatabaseOperations):
|
||||||
"exact": SDOOperator(func="SDO_EQUAL"),
|
"exact": SDOOperator(func="SDO_EQUAL"),
|
||||||
"overlaps": SDOOperator(func="SDO_OVERLAPS"),
|
"overlaps": SDOOperator(func="SDO_OVERLAPS"),
|
||||||
"same_as": SDOOperator(func="SDO_EQUAL"),
|
"same_as": SDOOperator(func="SDO_EQUAL"),
|
||||||
"relate": SDORelate(), # Oracle uses a different syntax, e.g., 'mask=inside+touch'
|
# Oracle uses a different syntax, e.g., 'mask=inside+touch'
|
||||||
|
"relate": SDORelate(),
|
||||||
"touches": SDOOperator(func="SDO_TOUCH"),
|
"touches": SDOOperator(func="SDO_TOUCH"),
|
||||||
"within": SDOOperator(func="SDO_INSIDE"),
|
"within": SDOOperator(func="SDO_INSIDE"),
|
||||||
"dwithin": SDODWithin(),
|
"dwithin": SDODWithin(),
|
||||||
|
|
|
@ -16,7 +16,10 @@ class OracleGISSchemaEditor(DatabaseSchemaEditor):
|
||||||
),
|
),
|
||||||
%(srid)s
|
%(srid)s
|
||||||
)"""
|
)"""
|
||||||
sql_add_spatial_index = "CREATE INDEX %(index)s ON %(table)s(%(column)s) INDEXTYPE IS MDSYS.SPATIAL_INDEX"
|
sql_add_spatial_index = (
|
||||||
|
"CREATE INDEX %(index)s ON %(table)s(%(column)s) "
|
||||||
|
"INDEXTYPE IS MDSYS.SPATIAL_INDEX"
|
||||||
|
)
|
||||||
sql_drop_spatial_index = "DROP INDEX %(index)s"
|
sql_drop_spatial_index = "DROP INDEX %(index)s"
|
||||||
sql_clear_geometry_table_metadata = (
|
sql_clear_geometry_table_metadata = (
|
||||||
"DELETE FROM USER_SDO_GEOM_METADATA WHERE TABLE_NAME = %(table)s"
|
"DELETE FROM USER_SDO_GEOM_METADATA WHERE TABLE_NAME = %(table)s"
|
||||||
|
|
|
@ -56,7 +56,7 @@ STRUCT_SIZE = {
|
||||||
# whether the band data is stored as part of the datum or is to be found on the
|
# whether the band data is stored as part of the datum or is to be found on the
|
||||||
# server's filesystem. There are currently 11 supported pixel value types, so 4
|
# server's filesystem. There are currently 11 supported pixel value types, so 4
|
||||||
# bits are enough to account for all. Reserve the upper 4 bits for generic
|
# bits are enough to account for all. Reserve the upper 4 bits for generic
|
||||||
# flags.
|
# flags. See
|
||||||
# See https://trac.osgeo.org/postgis/wiki/WKTRaster/RFC/RFC1_V0SerialFormat#Pixeltypeandstorageflag
|
# https://trac.osgeo.org/postgis/wiki/WKTRaster/RFC/RFC1_V0SerialFormat#Pixeltypeandstorageflag
|
||||||
BANDTYPE_PIXTYPE_MASK = 0x0F
|
BANDTYPE_PIXTYPE_MASK = 0x0F
|
||||||
BANDTYPE_FLAG_HASNODATA = 1 << 6
|
BANDTYPE_FLAG_HASNODATA = 1 << 6
|
||||||
|
|
|
@ -22,7 +22,9 @@ class PostGISIntrospection(DatabaseIntrospection):
|
||||||
# dictionary isn't updated until introspection is performed here.
|
# dictionary isn't updated until introspection is performed here.
|
||||||
with self.connection.cursor() as cursor:
|
with self.connection.cursor() as cursor:
|
||||||
cursor.execute(
|
cursor.execute(
|
||||||
"SELECT oid, typname FROM pg_type WHERE typname IN ('geometry', 'geography')"
|
"SELECT oid, typname "
|
||||||
|
"FROM pg_type "
|
||||||
|
"WHERE typname IN ('geometry', 'geography')"
|
||||||
)
|
)
|
||||||
self.postgis_oid_lookup = dict(cursor.fetchall())
|
self.postgis_oid_lookup = dict(cursor.fetchall())
|
||||||
self.data_types_reverse.update(
|
self.data_types_reverse.update(
|
||||||
|
|
|
@ -56,7 +56,8 @@ class PostGISOperator(SpatialOperator):
|
||||||
if lookup.band_lhs is not None and lhs_is_raster:
|
if lookup.band_lhs is not None and lhs_is_raster:
|
||||||
if not self.func:
|
if not self.func:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
"Band indices are not allowed for this operator, it works on bbox only."
|
"Band indices are not allowed for this operator, it works on bbox "
|
||||||
|
"only."
|
||||||
)
|
)
|
||||||
template_params["lhs"] = "%s, %s" % (
|
template_params["lhs"] = "%s, %s" % (
|
||||||
template_params["lhs"],
|
template_params["lhs"],
|
||||||
|
@ -66,7 +67,8 @@ class PostGISOperator(SpatialOperator):
|
||||||
if lookup.band_rhs is not None and rhs_is_raster:
|
if lookup.band_rhs is not None and rhs_is_raster:
|
||||||
if not self.func:
|
if not self.func:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
"Band indices are not allowed for this operator, it works on bbox only."
|
"Band indices are not allowed for this operator, it works on bbox "
|
||||||
|
"only."
|
||||||
)
|
)
|
||||||
template_params["rhs"] = "%s, %s" % (
|
template_params["rhs"] = "%s, %s" % (
|
||||||
template_params["rhs"],
|
template_params["rhs"],
|
||||||
|
|
|
@ -317,9 +317,11 @@ class Distance(DistanceResultMixin, OracleToleranceMixin, GeoFunc):
|
||||||
)
|
)
|
||||||
|
|
||||||
if not geography and self.geo_field.geodetic(connection):
|
if not geography and self.geo_field.geodetic(connection):
|
||||||
# Geometry fields with geodetic (lon/lat) coordinates need special distance functions
|
# Geometry fields with geodetic (lon/lat) coordinates need special
|
||||||
|
# distance functions.
|
||||||
if self.spheroid:
|
if self.spheroid:
|
||||||
# DistanceSpheroid is more accurate and resource intensive than DistanceSphere
|
# DistanceSpheroid is more accurate and resource intensive than
|
||||||
|
# DistanceSphere.
|
||||||
function = connection.ops.spatial_function_name("DistanceSpheroid")
|
function = connection.ops.spatial_function_name("DistanceSpheroid")
|
||||||
# Replace boolean param by the real spheroid of the base field
|
# Replace boolean param by the real spheroid of the base field
|
||||||
clone.source_expressions.append(
|
clone.source_expressions.append(
|
||||||
|
|
|
@ -202,7 +202,8 @@ class BBContainsLookup(GISLookup):
|
||||||
@BaseSpatialField.register_lookup
|
@BaseSpatialField.register_lookup
|
||||||
class BBOverlapsLookup(GISLookup):
|
class BBOverlapsLookup(GISLookup):
|
||||||
"""
|
"""
|
||||||
The 'bboverlaps' operator returns true if A's bounding box overlaps B's bounding box.
|
The 'bboverlaps' operator returns true if A's bounding box overlaps B's
|
||||||
|
bounding box.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
lookup_name = "bboverlaps"
|
lookup_name = "bboverlaps"
|
||||||
|
@ -307,7 +308,8 @@ class DistanceLookupBase(GISLookup):
|
||||||
)
|
)
|
||||||
elif len(self.rhs_params) == 3 and self.rhs_params[2] != "spheroid":
|
elif len(self.rhs_params) == 3 and self.rhs_params[2] != "spheroid":
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
"For 4-element tuples the last argument must be the 'spheroid' directive."
|
"For 4-element tuples the last argument must be the 'spheroid' "
|
||||||
|
"directive."
|
||||||
)
|
)
|
||||||
|
|
||||||
# Check if the second parameter is a band index.
|
# Check if the second parameter is a band index.
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
>>> print(mpnt.proj)
|
>>> print(mpnt.proj)
|
||||||
+proj=longlat +ellps=clrk66 +datum=NAD27 +no_defs
|
+proj=longlat +ellps=clrk66 +datum=NAD27 +no_defs
|
||||||
>>> print(mpnt)
|
>>> print(mpnt)
|
||||||
MULTIPOINT (-89.999930378602485 29.999797886557641,-89.999930378602485 29.999797886557641)
|
MULTIPOINT (-89.99993037860248 29.99979788655764,-89.99993037860248 29.99979788655764)
|
||||||
|
|
||||||
The OGRGeomType class is to make it easy to specify an OGR geometry type:
|
The OGRGeomType class is to make it easy to specify an OGR geometry type:
|
||||||
>>> from django.contrib.gis.gdal import OGRGeomType
|
>>> from django.contrib.gis.gdal import OGRGeomType
|
||||||
|
|
|
@ -19,7 +19,10 @@ from django.utils.encoding import force_bytes, force_str
|
||||||
#
|
#
|
||||||
# The OGR_L_* routines are relevant here.
|
# The OGR_L_* routines are relevant here.
|
||||||
class Layer(GDALBase):
|
class Layer(GDALBase):
|
||||||
"A class that wraps an OGR Layer, needs to be instantiated from a DataSource object."
|
"""
|
||||||
|
A class that wraps an OGR Layer, needs to be instantiated from a DataSource
|
||||||
|
object.
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self, layer_ptr, ds):
|
def __init__(self, layer_ptr, ds):
|
||||||
"""
|
"""
|
||||||
|
@ -192,7 +195,8 @@ class Layer(GDALBase):
|
||||||
capi.set_spatial_filter(self.ptr, None)
|
capi.set_spatial_filter(self.ptr, None)
|
||||||
else:
|
else:
|
||||||
raise TypeError(
|
raise TypeError(
|
||||||
"Spatial filter must be either an OGRGeometry instance, a 4-tuple, or None."
|
"Spatial filter must be either an OGRGeometry instance, a 4-tuple, or "
|
||||||
|
"None."
|
||||||
)
|
)
|
||||||
|
|
||||||
spatial_filter = property(_get_spatial_filter, _set_spatial_filter)
|
spatial_filter = property(_get_spatial_filter, _set_spatial_filter)
|
||||||
|
|
|
@ -131,7 +131,8 @@ class SpatialReference(GDALBase):
|
||||||
4326
|
4326
|
||||||
>>> print(srs['TOWGS84', 4]) # the fourth value in this wkt
|
>>> print(srs['TOWGS84', 4]) # the fourth value in this wkt
|
||||||
0
|
0
|
||||||
>>> print(srs['UNIT|AUTHORITY']) # For the units authority, have to use the pipe symbole.
|
>>> # For the units authority, have to use the pipe symbole.
|
||||||
|
>>> print(srs['UNIT|AUTHORITY'])
|
||||||
EPSG
|
EPSG
|
||||||
>>> print(srs['UNIT|AUTHORITY', 1]) # The authority value for the units
|
>>> print(srs['UNIT|AUTHORITY', 1]) # The authority value for the units
|
||||||
9122
|
9122
|
||||||
|
|
|
@ -32,7 +32,8 @@ class Polygon(GEOSGeometry):
|
||||||
ext_ring, *init_holes = args
|
ext_ring, *init_holes = args
|
||||||
n_holes = len(init_holes)
|
n_holes = len(init_holes)
|
||||||
|
|
||||||
# If initialized as Polygon(shell, (LinearRing, LinearRing)) [for backward-compatibility]
|
# If initialized as Polygon(shell, (LinearRing, LinearRing))
|
||||||
|
# [for backward-compatibility]
|
||||||
if n_holes == 1 and isinstance(init_holes[0], (tuple, list)):
|
if n_holes == 1 and isinstance(init_holes[0], (tuple, list)):
|
||||||
if not init_holes[0]:
|
if not init_holes[0]:
|
||||||
init_holes = ()
|
init_holes = ()
|
||||||
|
@ -101,7 +102,8 @@ class Polygon(GEOSGeometry):
|
||||||
self,
|
self,
|
||||||
param,
|
param,
|
||||||
msg=(
|
msg=(
|
||||||
"Parameter must be a sequence of LinearRings or objects that can initialize to LinearRings"
|
"Parameter must be a sequence of LinearRings or objects that can "
|
||||||
|
"initialize to LinearRings"
|
||||||
),
|
),
|
||||||
):
|
):
|
||||||
"Try to construct a ring from the given parameter."
|
"Try to construct a ring from the given parameter."
|
||||||
|
|
|
@ -34,8 +34,8 @@ class ListOptionAction(argparse.Action):
|
||||||
|
|
||||||
class Command(BaseCommand):
|
class Command(BaseCommand):
|
||||||
help = (
|
help = (
|
||||||
"Inspects the given OGR-compatible data source (e.g., a shapefile) and outputs\n"
|
"Inspects the given OGR-compatible data source (e.g., a shapefile) and "
|
||||||
"a GeoDjango model with the given model name. For example:\n"
|
"outputs\na GeoDjango model with the given model name. For example:\n"
|
||||||
" ./manage.py ogrinspect zipcode.shp Zipcode"
|
" ./manage.py ogrinspect zipcode.shp Zipcode"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,8 @@ class Serializer(JSONSerializer):
|
||||||
self._init_options()
|
self._init_options()
|
||||||
self._cts = {} # cache of CoordTransform's
|
self._cts = {} # cache of CoordTransform's
|
||||||
self.stream.write(
|
self.stream.write(
|
||||||
'{"type": "FeatureCollection", "crs": {"type": "name", "properties": {"name": "EPSG:%d"}},'
|
'{"type": "FeatureCollection", '
|
||||||
|
'"crs": {"type": "name", "properties": {"name": "EPSG:%d"}},'
|
||||||
' "features": [' % self.srid
|
' "features": [' % self.srid
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -53,7 +54,8 @@ class Serializer(JSONSerializer):
|
||||||
data["properties"]["pk"] = obj._meta.pk.value_to_string(obj)
|
data["properties"]["pk"] = obj._meta.pk.value_to_string(obj)
|
||||||
if self._geometry:
|
if self._geometry:
|
||||||
if self._geometry.srid != self.srid:
|
if self._geometry.srid != self.srid:
|
||||||
# If needed, transform the geometry in the srid of the global geojson srid
|
# If needed, transform the geometry in the srid of the global
|
||||||
|
# geojson srid.
|
||||||
if self._geometry.srid not in self._cts:
|
if self._geometry.srid not in self._cts:
|
||||||
srs = SpatialReference(self.srid)
|
srs = SpatialReference(self.srid)
|
||||||
self._cts[self._geometry.srid] = CoordTransform(
|
self._cts[self._geometry.srid] = CoordTransform(
|
||||||
|
|
|
@ -42,7 +42,8 @@ class KMLSitemap(Sitemap):
|
||||||
elif isinstance(source, (list, tuple)):
|
elif isinstance(source, (list, tuple)):
|
||||||
if len(source) != 3:
|
if len(source) != 3:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
"Must specify a 3-tuple of (app_label, module_name, field_name)."
|
"Must specify a 3-tuple of (app_label, module_name, "
|
||||||
|
"field_name)."
|
||||||
)
|
)
|
||||||
kml_sources.append(source)
|
kml_sources.append(source)
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -233,7 +233,8 @@ class LayerMapping:
|
||||||
if isinstance(model_field, GeometryField):
|
if isinstance(model_field, GeometryField):
|
||||||
if self.geom_field:
|
if self.geom_field:
|
||||||
raise LayerMapError(
|
raise LayerMapError(
|
||||||
"LayerMapping does not support more than one GeometryField per model."
|
"LayerMapping does not support more than one GeometryField per "
|
||||||
|
"model."
|
||||||
)
|
)
|
||||||
|
|
||||||
# Getting the coordinate dimension of the geometry field.
|
# Getting the coordinate dimension of the geometry field.
|
||||||
|
@ -695,7 +696,8 @@ class LayerMapping:
|
||||||
# Incremental saving is requested at the given interval (step)
|
# Incremental saving is requested at the given interval (step)
|
||||||
if default_range:
|
if default_range:
|
||||||
raise LayerMapError(
|
raise LayerMapError(
|
||||||
"The `step` keyword may not be used in conjunction with the `fid_range` keyword."
|
"The `step` keyword may not be used in conjunction with the "
|
||||||
|
"`fid_range` keyword."
|
||||||
)
|
)
|
||||||
beg, num_feat, num_saved = (0, 0, 0)
|
beg, num_feat, num_saved = (0, 0, 0)
|
||||||
indices = range(step, nfeat, step)
|
indices = range(step, nfeat, step)
|
||||||
|
|
|
@ -209,7 +209,9 @@ def _ogrinspect(
|
||||||
# may also be mapped to `DecimalField` if specified in the
|
# may also be mapped to `DecimalField` if specified in the
|
||||||
# `decimal` keyword.
|
# `decimal` keyword.
|
||||||
if field_name.lower() in decimal_fields:
|
if field_name.lower() in decimal_fields:
|
||||||
yield " %s = models.DecimalField(max_digits=%d, decimal_places=%d%s)" % (
|
yield (
|
||||||
|
" %s = models.DecimalField(max_digits=%d, decimal_places=%d%s)"
|
||||||
|
) % (
|
||||||
mfield,
|
mfield,
|
||||||
width,
|
width,
|
||||||
precision,
|
precision,
|
||||||
|
|
|
@ -256,7 +256,8 @@ class NaturalTimeFormatter:
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
future_substrings = {
|
future_substrings = {
|
||||||
# Translators: 'naturaltime-future' strings will be included in '%(delta)s from now'
|
# Translators: 'naturaltime-future' strings will be included in
|
||||||
|
# '%(delta)s from now'.
|
||||||
"year": npgettext_lazy(
|
"year": npgettext_lazy(
|
||||||
"naturaltime-future", "%(num)d year", "%(num)d years", "num"
|
"naturaltime-future", "%(num)d year", "%(num)d years", "num"
|
||||||
),
|
),
|
||||||
|
|
|
@ -18,7 +18,10 @@ class ExclusionConstraintExpression(IndexExpression):
|
||||||
|
|
||||||
|
|
||||||
class ExclusionConstraint(BaseConstraint):
|
class ExclusionConstraint(BaseConstraint):
|
||||||
template = "CONSTRAINT %(name)s EXCLUDE USING %(index_type)s (%(expressions)s)%(include)s%(where)s%(deferrable)s"
|
template = (
|
||||||
|
"CONSTRAINT %(name)s EXCLUDE USING %(index_type)s "
|
||||||
|
"(%(expressions)s)%(include)s%(where)s%(deferrable)s"
|
||||||
|
)
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
|
|
|
@ -54,7 +54,8 @@ class RangeField(models.Field):
|
||||||
raise TypeError(
|
raise TypeError(
|
||||||
f"Cannot use 'default_bounds' with {self.__class__.__name__}."
|
f"Cannot use 'default_bounds' with {self.__class__.__name__}."
|
||||||
)
|
)
|
||||||
# Initializing base_field here ensures that its model matches the model for self.
|
# Initializing base_field here ensures that its model matches the model
|
||||||
|
# for self.
|
||||||
if hasattr(self, "base_field"):
|
if hasattr(self, "base_field"):
|
||||||
self.base_field = self.base_field()
|
self.base_field = self.base_field()
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|
|
@ -185,9 +185,8 @@ class CollationOperation(Operation):
|
||||||
)
|
)
|
||||||
|
|
||||||
def create_collation(self, schema_editor):
|
def create_collation(self, schema_editor):
|
||||||
if (
|
if self.deterministic is False and not (
|
||||||
self.deterministic is False
|
schema_editor.connection.features.supports_non_deterministic_collations
|
||||||
and not schema_editor.connection.features.supports_non_deterministic_collations
|
|
||||||
):
|
):
|
||||||
raise NotSupportedError(
|
raise NotSupportedError(
|
||||||
"Non-deterministic collations require PostgreSQL 12+."
|
"Non-deterministic collations require PostgreSQL 12+."
|
||||||
|
|
|
@ -12,16 +12,20 @@ from django.utils.translation import ngettext_lazy
|
||||||
|
|
||||||
class ArrayMaxLengthValidator(MaxLengthValidator):
|
class ArrayMaxLengthValidator(MaxLengthValidator):
|
||||||
message = ngettext_lazy(
|
message = ngettext_lazy(
|
||||||
"List contains %(show_value)d item, it should contain no more than %(limit_value)d.",
|
"List contains %(show_value)d item, it should contain no more than "
|
||||||
"List contains %(show_value)d items, it should contain no more than %(limit_value)d.",
|
"%(limit_value)d.",
|
||||||
|
"List contains %(show_value)d items, it should contain no more than "
|
||||||
|
"%(limit_value)d.",
|
||||||
"limit_value",
|
"limit_value",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class ArrayMinLengthValidator(MinLengthValidator):
|
class ArrayMinLengthValidator(MinLengthValidator):
|
||||||
message = ngettext_lazy(
|
message = ngettext_lazy(
|
||||||
"List contains %(show_value)d item, it should contain no fewer than %(limit_value)d.",
|
"List contains %(show_value)d item, it should contain no fewer than "
|
||||||
"List contains %(show_value)d items, it should contain no fewer than %(limit_value)d.",
|
"%(limit_value)d.",
|
||||||
|
"List contains %(show_value)d items, it should contain no fewer than "
|
||||||
|
"%(limit_value)d.",
|
||||||
"limit_value",
|
"limit_value",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,8 @@ class Migration(migrations.Migration):
|
||||||
"old_path",
|
"old_path",
|
||||||
models.CharField(
|
models.CharField(
|
||||||
help_text=(
|
help_text=(
|
||||||
"This should be an absolute path, excluding the domain name. Example: “/events/search/”."
|
"This should be an absolute path, excluding the domain "
|
||||||
|
"name. Example: “/events/search/”."
|
||||||
),
|
),
|
||||||
max_length=200,
|
max_length=200,
|
||||||
verbose_name="redirect from",
|
verbose_name="redirect from",
|
||||||
|
@ -42,7 +43,10 @@ class Migration(migrations.Migration):
|
||||||
(
|
(
|
||||||
"new_path",
|
"new_path",
|
||||||
models.CharField(
|
models.CharField(
|
||||||
help_text="This can be either an absolute path (as above) or a full URL starting with “http://”.",
|
help_text=(
|
||||||
|
"This can be either an absolute path (as above) or a full "
|
||||||
|
"URL starting with “http://”."
|
||||||
|
),
|
||||||
max_length=200,
|
max_length=200,
|
||||||
verbose_name="redirect to",
|
verbose_name="redirect to",
|
||||||
blank=True,
|
blank=True,
|
||||||
|
|
|
@ -10,7 +10,8 @@ class Redirect(models.Model):
|
||||||
max_length=200,
|
max_length=200,
|
||||||
db_index=True,
|
db_index=True,
|
||||||
help_text=_(
|
help_text=_(
|
||||||
"This should be an absolute path, excluding the domain name. Example: “/events/search/”."
|
"This should be an absolute path, excluding the domain name. Example: "
|
||||||
|
"“/events/search/”."
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
new_path = models.CharField(
|
new_path = models.CharField(
|
||||||
|
|
|
@ -48,7 +48,8 @@ def _get_sitemap_full_url(sitemap_url, sitemap_uses_https=True):
|
||||||
|
|
||||||
if sitemap_url is None:
|
if sitemap_url is None:
|
||||||
raise SitemapNotFound(
|
raise SitemapNotFound(
|
||||||
"You didn't provide a sitemap_url, and the sitemap URL couldn't be auto-detected."
|
"You didn't provide a sitemap_url, and the sitemap URL couldn't be "
|
||||||
|
"auto-detected."
|
||||||
)
|
)
|
||||||
|
|
||||||
Site = django_apps.get_model("sites.Site")
|
Site = django_apps.get_model("sites.Site")
|
||||||
|
|
|
@ -20,7 +20,10 @@ class SitemapIndexItem:
|
||||||
|
|
||||||
# RemovedInDjango50Warning
|
# RemovedInDjango50Warning
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
msg = "Calling `__str__` on SitemapIndexItem is deprecated, use the `location` attribute instead."
|
msg = (
|
||||||
|
"Calling `__str__` on SitemapIndexItem is deprecated, use the `location` "
|
||||||
|
"attribute instead."
|
||||||
|
)
|
||||||
warnings.warn(msg, RemovedInDjango50Warning, stacklevel=2)
|
warnings.warn(msg, RemovedInDjango50Warning, stacklevel=2)
|
||||||
return self.location
|
return self.location
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,8 @@ class CurrentSiteManager(models.Manager):
|
||||||
if not field.many_to_many and not isinstance(field, (models.ForeignKey)):
|
if not field.many_to_many and not isinstance(field, (models.ForeignKey)):
|
||||||
return [
|
return [
|
||||||
checks.Error(
|
checks.Error(
|
||||||
"CurrentSiteManager cannot use '%s.%s' as it is not a foreign key or a many-to-many field."
|
"CurrentSiteManager cannot use '%s.%s' as it is not a foreign key "
|
||||||
|
"or a many-to-many field."
|
||||||
% (self.model._meta.object_name, field_name),
|
% (self.model._meta.object_name, field_name),
|
||||||
obj=self,
|
obj=self,
|
||||||
id="sites.E002",
|
id="sites.E002",
|
||||||
|
|
|
@ -83,7 +83,10 @@ class Command(BaseCommand):
|
||||||
"--no-default-ignore",
|
"--no-default-ignore",
|
||||||
action="store_false",
|
action="store_false",
|
||||||
dest="use_default_ignore_patterns",
|
dest="use_default_ignore_patterns",
|
||||||
help="Don't ignore the common private glob-style patterns (defaults to 'CVS', '.*' and '*~').",
|
help=(
|
||||||
|
"Don't ignore the common private glob-style patterns (defaults to "
|
||||||
|
"'CVS', '.*' and '*~')."
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
def set_options(self, **options):
|
def set_options(self, **options):
|
||||||
|
@ -169,7 +172,8 @@ class Command(BaseCommand):
|
||||||
message = ["\n"]
|
message = ["\n"]
|
||||||
if self.dry_run:
|
if self.dry_run:
|
||||||
message.append(
|
message.append(
|
||||||
"You have activated the --dry-run option so no files will be modified.\n\n"
|
"You have activated the --dry-run option so no files will be "
|
||||||
|
"modified.\n\n"
|
||||||
)
|
)
|
||||||
|
|
||||||
message.append(
|
message.append(
|
||||||
|
|
|
@ -77,7 +77,8 @@ class BaseMemcachedCache(BaseCache):
|
||||||
def set(self, key, value, timeout=DEFAULT_TIMEOUT, version=None):
|
def set(self, key, value, timeout=DEFAULT_TIMEOUT, version=None):
|
||||||
key = self.make_and_validate_key(key, version=version)
|
key = self.make_and_validate_key(key, version=version)
|
||||||
if not self._cache.set(key, value, self.get_backend_timeout(timeout)):
|
if not self._cache.set(key, value, self.get_backend_timeout(timeout)):
|
||||||
# make sure the key doesn't keep its old value in case of failure to set (memcached's 1MB limit)
|
# Make sure the key doesn't keep its old value in case of failure
|
||||||
|
# to set (memcached's 1MB limit).
|
||||||
self._cache.delete(key)
|
self._cache.delete(key)
|
||||||
|
|
||||||
def touch(self, key, timeout=DEFAULT_TIMEOUT, version=None):
|
def touch(self, key, timeout=DEFAULT_TIMEOUT, version=None):
|
||||||
|
|
|
@ -60,8 +60,8 @@ def check_csrf_failure_view(app_configs, **kwargs):
|
||||||
inspect.signature(view).bind(None, reason=None)
|
inspect.signature(view).bind(None, reason=None)
|
||||||
except TypeError:
|
except TypeError:
|
||||||
msg = (
|
msg = (
|
||||||
"The CSRF failure view '%s' does not take the correct number of arguments."
|
"The CSRF failure view '%s' does not take the correct number of "
|
||||||
% settings.CSRF_FAILURE_VIEW
|
"arguments." % settings.CSRF_FAILURE_VIEW
|
||||||
)
|
)
|
||||||
errors.append(Error(msg, id="security.E101"))
|
errors.append(Error(msg, id="security.E101"))
|
||||||
return errors
|
return errors
|
||||||
|
|
|
@ -6,7 +6,7 @@ Cookbook [1] (licensed under the Python Software License) and a ctypes port by
|
||||||
Anatoly Techtonik for Roundup [2] (license [3]).
|
Anatoly Techtonik for Roundup [2] (license [3]).
|
||||||
|
|
||||||
[1] https://code.activestate.com/recipes/65203/
|
[1] https://code.activestate.com/recipes/65203/
|
||||||
[2] https://sourceforge.net/p/roundup/code/ci/default/tree/roundup/backends/portalocker.py
|
[2] https://sourceforge.net/p/roundup/code/ci/default/tree/roundup/backends/portalocker.py # NOQA
|
||||||
[3] https://sourceforge.net/p/roundup/code/ci/default/tree/COPYING.txt
|
[3] https://sourceforge.net/p/roundup/code/ci/default/tree/COPYING.txt
|
||||||
|
|
||||||
Example Usage::
|
Example Usage::
|
||||||
|
|
|
@ -104,7 +104,8 @@ class Storage:
|
||||||
truncation = len(name) - max_length
|
truncation = len(name) - max_length
|
||||||
if truncation > 0:
|
if truncation > 0:
|
||||||
file_root = file_root[:-truncation]
|
file_root = file_root[:-truncation]
|
||||||
# Entire file_root was truncated in attempt to find an available filename.
|
# Entire file_root was truncated in attempt to find an
|
||||||
|
# available filename.
|
||||||
if not file_root:
|
if not file_root:
|
||||||
raise SuspiciousFileOperation(
|
raise SuspiciousFileOperation(
|
||||||
'Storage can not find an available filename for "%s". '
|
'Storage can not find an available filename for "%s". '
|
||||||
|
|
|
@ -242,7 +242,10 @@ def load_handler(path, *args, **kwargs):
|
||||||
E.g.::
|
E.g.::
|
||||||
>>> from django.http import HttpRequest
|
>>> from django.http import HttpRequest
|
||||||
>>> request = HttpRequest()
|
>>> request = HttpRequest()
|
||||||
>>> load_handler('django.core.files.uploadhandler.TemporaryFileUploadHandler', request)
|
>>> load_handler(
|
||||||
|
... 'django.core.files.uploadhandler.TemporaryFileUploadHandler',
|
||||||
|
... request,
|
||||||
|
... )
|
||||||
<TemporaryFileUploadHandler object at 0x...>
|
<TemporaryFileUploadHandler object at 0x...>
|
||||||
"""
|
"""
|
||||||
return import_string(path)(*args, **kwargs)
|
return import_string(path)(*args, **kwargs)
|
||||||
|
|
|
@ -208,7 +208,8 @@ class BaseHandler:
|
||||||
if hasattr(response, "render") and callable(response.render):
|
if hasattr(response, "render") and callable(response.render):
|
||||||
for middleware_method in self._template_response_middleware:
|
for middleware_method in self._template_response_middleware:
|
||||||
response = middleware_method(request, response)
|
response = middleware_method(request, response)
|
||||||
# Complain if the template response middleware returned None (a common error).
|
# Complain if the template response middleware returned None
|
||||||
|
# (a common error).
|
||||||
self.check_response(
|
self.check_response(
|
||||||
response,
|
response,
|
||||||
middleware_method,
|
middleware_method,
|
||||||
|
|
|
@ -308,7 +308,10 @@ class BaseCommand:
|
||||||
default=1,
|
default=1,
|
||||||
type=int,
|
type=int,
|
||||||
choices=[0, 1, 2, 3],
|
choices=[0, 1, 2, 3],
|
||||||
help="Verbosity level; 0=minimal output, 1=normal output, 2=verbose output, 3=very verbose output",
|
help=(
|
||||||
|
"Verbosity level; 0=minimal output, 1=normal output, 2=verbose output, "
|
||||||
|
"3=very verbose output"
|
||||||
|
),
|
||||||
)
|
)
|
||||||
self.add_base_argument(
|
self.add_base_argument(
|
||||||
parser,
|
parser,
|
||||||
|
@ -322,7 +325,10 @@ class BaseCommand:
|
||||||
self.add_base_argument(
|
self.add_base_argument(
|
||||||
parser,
|
parser,
|
||||||
"--pythonpath",
|
"--pythonpath",
|
||||||
help='A directory to add to the Python path, e.g. "/home/djangoprojects/myproject".',
|
help=(
|
||||||
|
"A directory to add to the Python path, e.g. "
|
||||||
|
'"/home/djangoprojects/myproject".'
|
||||||
|
),
|
||||||
)
|
)
|
||||||
self.add_base_argument(
|
self.add_base_argument(
|
||||||
parser,
|
parser,
|
||||||
|
|
|
@ -173,8 +173,8 @@ class Command(BaseCommand):
|
||||||
# Check writability on first location
|
# Check writability on first location
|
||||||
if i == 0 and not is_writable(mo_path):
|
if i == 0 and not is_writable(mo_path):
|
||||||
self.stderr.write(
|
self.stderr.write(
|
||||||
"The po files under %s are in a seemingly not writable location. "
|
"The po files under %s are in a seemingly not writable "
|
||||||
"mo files will not be updated/created." % dirpath
|
"location. mo files will not be updated/created." % dirpath
|
||||||
)
|
)
|
||||||
self.has_errors = True
|
self.has_errors = True
|
||||||
return
|
return
|
||||||
|
|
|
@ -22,7 +22,10 @@ class Command(BaseCommand):
|
||||||
"args",
|
"args",
|
||||||
metavar="table_name",
|
metavar="table_name",
|
||||||
nargs="*",
|
nargs="*",
|
||||||
help="Optional table names. Otherwise, settings.CACHES is used to find cache tables.",
|
help=(
|
||||||
|
"Optional table names. Otherwise, settings.CACHES is used to find "
|
||||||
|
"cache tables."
|
||||||
|
),
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--database",
|
"--database",
|
||||||
|
|
|
@ -16,7 +16,10 @@ class Command(BaseCommand):
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--database",
|
"--database",
|
||||||
default=DEFAULT_DB_ALIAS,
|
default=DEFAULT_DB_ALIAS,
|
||||||
help='Nominates a database onto which to open a shell. Defaults to the "default" database.',
|
help=(
|
||||||
|
"Nominates a database onto which to open a shell. Defaults to the "
|
||||||
|
'"default" database.'
|
||||||
|
),
|
||||||
)
|
)
|
||||||
parameters = parser.add_argument_group("parameters", prefix_chars="--")
|
parameters = parser.add_argument_group("parameters", prefix_chars="--")
|
||||||
parameters.add_argument("parameters", nargs="*")
|
parameters.add_argument("parameters", nargs="*")
|
||||||
|
|
|
@ -25,8 +25,8 @@ class Command(BaseCommand):
|
||||||
"--default",
|
"--default",
|
||||||
metavar="MODULE",
|
metavar="MODULE",
|
||||||
help=(
|
help=(
|
||||||
"The settings module to compare the current settings against. Leave empty to "
|
"The settings module to compare the current settings against. Leave "
|
||||||
"compare against Django's default settings."
|
"empty to compare against Django's default settings."
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
|
|
|
@ -38,7 +38,10 @@ class Command(BaseCommand):
|
||||||
"args",
|
"args",
|
||||||
metavar="app_label[.ModelName]",
|
metavar="app_label[.ModelName]",
|
||||||
nargs="*",
|
nargs="*",
|
||||||
help="Restricts dumped data to the specified app_label or app_label.ModelName.",
|
help=(
|
||||||
|
"Restricts dumped data to the specified app_label or "
|
||||||
|
"app_label.ModelName."
|
||||||
|
),
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--format",
|
"--format",
|
||||||
|
@ -81,8 +84,11 @@ class Command(BaseCommand):
|
||||||
"--all",
|
"--all",
|
||||||
action="store_true",
|
action="store_true",
|
||||||
dest="use_base_manager",
|
dest="use_base_manager",
|
||||||
help="Use Django's base manager to dump all models stored in the database, "
|
help=(
|
||||||
"including those that would otherwise be filtered or modified by a custom manager.",
|
"Use Django's base manager to dump all models stored in the database, "
|
||||||
|
"including those that would otherwise be filtered or modified by a "
|
||||||
|
"custom manager."
|
||||||
|
),
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--pks",
|
"--pks",
|
||||||
|
|
|
@ -82,7 +82,8 @@ Are you sure you want to do this?
|
||||||
% (connection.settings_dict["NAME"],)
|
% (connection.settings_dict["NAME"],)
|
||||||
) from exc
|
) from exc
|
||||||
|
|
||||||
# Empty sql_list may signify an empty database and post_migrate would then crash
|
# Empty sql_list may signify an empty database and post_migrate
|
||||||
|
# would then crash.
|
||||||
if sql_list and not inhibit_post_migrate:
|
if sql_list and not inhibit_post_migrate:
|
||||||
# Emit the post migrate signal. This allows individual applications to
|
# Emit the post migrate signal. This allows individual applications to
|
||||||
# respond as if the database had been migrated from scratch.
|
# respond as if the database had been migrated from scratch.
|
||||||
|
|
|
@ -7,7 +7,10 @@ from django.db.models.constants import LOOKUP_SEP
|
||||||
|
|
||||||
|
|
||||||
class Command(BaseCommand):
|
class Command(BaseCommand):
|
||||||
help = "Introspects the database tables in the given database and outputs a Django model module."
|
help = (
|
||||||
|
"Introspects the database tables in the given database and outputs a Django "
|
||||||
|
"model module."
|
||||||
|
)
|
||||||
requires_system_checks = []
|
requires_system_checks = []
|
||||||
stealth_options = ("table_name_filter",)
|
stealth_options = ("table_name_filter",)
|
||||||
db_module = "django.db"
|
db_module = "django.db"
|
||||||
|
@ -22,7 +25,10 @@ class Command(BaseCommand):
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--database",
|
"--database",
|
||||||
default=DEFAULT_DB_ALIAS,
|
default=DEFAULT_DB_ALIAS,
|
||||||
help='Nominates a database to introspect. Defaults to using the "default" database.',
|
help=(
|
||||||
|
'Nominates a database to introspect. Defaults to using the "default" '
|
||||||
|
"database."
|
||||||
|
),
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--include-partitions",
|
"--include-partitions",
|
||||||
|
@ -41,7 +47,8 @@ class Command(BaseCommand):
|
||||||
self.stdout.write(line)
|
self.stdout.write(line)
|
||||||
except NotImplementedError:
|
except NotImplementedError:
|
||||||
raise CommandError(
|
raise CommandError(
|
||||||
"Database inspection isn't supported for the currently selected database backend."
|
"Database inspection isn't supported for the currently selected "
|
||||||
|
"database backend."
|
||||||
)
|
)
|
||||||
|
|
||||||
def handle_inspection(self, options):
|
def handle_inspection(self, options):
|
||||||
|
@ -57,12 +64,18 @@ class Command(BaseCommand):
|
||||||
yield "# You'll have to do the following manually to clean this up:"
|
yield "# You'll have to do the following manually to clean this up:"
|
||||||
yield "# * Rearrange models' order"
|
yield "# * Rearrange models' order"
|
||||||
yield "# * Make sure each model has one field with primary_key=True"
|
yield "# * Make sure each model has one field with primary_key=True"
|
||||||
yield "# * Make sure each ForeignKey and OneToOneField has `on_delete` set to the desired behavior"
|
yield (
|
||||||
|
"# * Make sure each ForeignKey and OneToOneField has `on_delete` set "
|
||||||
|
"to the desired behavior"
|
||||||
|
)
|
||||||
yield (
|
yield (
|
||||||
"# * Remove `managed = False` lines if you wish to allow "
|
"# * Remove `managed = False` lines if you wish to allow "
|
||||||
"Django to create, modify, and delete the table"
|
"Django to create, modify, and delete the table"
|
||||||
)
|
)
|
||||||
yield "# Feel free to rename the models, but don't rename db_table values or field names."
|
yield (
|
||||||
|
"# Feel free to rename the models, but don't rename db_table values or "
|
||||||
|
"field names."
|
||||||
|
)
|
||||||
yield "from %s import models" % self.db_module
|
yield "from %s import models" % self.db_module
|
||||||
known_models = []
|
known_models = []
|
||||||
table_info = connection.introspection.get_table_list(cursor)
|
table_info = connection.introspection.get_table_list(cursor)
|
||||||
|
|
|
@ -55,7 +55,10 @@ class Command(BaseCommand):
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--database",
|
"--database",
|
||||||
default=DEFAULT_DB_ALIAS,
|
default=DEFAULT_DB_ALIAS,
|
||||||
help='Nominates a specific database to load fixtures into. Defaults to the "default" database.',
|
help=(
|
||||||
|
"Nominates a specific database to load fixtures into. Defaults to the "
|
||||||
|
'"default" database.'
|
||||||
|
),
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--app",
|
"--app",
|
||||||
|
@ -75,7 +78,10 @@ class Command(BaseCommand):
|
||||||
"--exclude",
|
"--exclude",
|
||||||
action="append",
|
action="append",
|
||||||
default=[],
|
default=[],
|
||||||
help="An app_label or app_label.ModelName to exclude. Can be used multiple times.",
|
help=(
|
||||||
|
"An app_label or app_label.ModelName to exclude. Can be used multiple "
|
||||||
|
"times."
|
||||||
|
),
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--format",
|
"--format",
|
||||||
|
@ -105,7 +111,8 @@ class Command(BaseCommand):
|
||||||
@cached_property
|
@cached_property
|
||||||
def compression_formats(self):
|
def compression_formats(self):
|
||||||
"""A dict mapping format names to (open function, mode arg) tuples."""
|
"""A dict mapping format names to (open function, mode arg) tuples."""
|
||||||
# Forcing binary mode may be revisited after dropping Python 2 support (see #22399)
|
# Forcing binary mode may be revisited after dropping Python 2 support
|
||||||
|
# (see #22399).
|
||||||
compression_formats = {
|
compression_formats = {
|
||||||
None: (open, "rb"),
|
None: (open, "rb"),
|
||||||
"gz": (gzip.GzipFile, "rb"),
|
"gz": (gzip.GzipFile, "rb"),
|
||||||
|
|
|
@ -203,11 +203,11 @@ def write_pot_file(potfile, msgs):
|
||||||
|
|
||||||
class Command(BaseCommand):
|
class Command(BaseCommand):
|
||||||
help = (
|
help = (
|
||||||
"Runs over the entire source tree of the current directory and "
|
"Runs over the entire source tree of the current directory and pulls out all "
|
||||||
"pulls out all strings marked for translation. It creates (or updates) a message "
|
"strings marked for translation. It creates (or updates) a message file in the "
|
||||||
"file in the conf/locale (in the django tree) or locale (for projects and "
|
"conf/locale (in the django tree) or locale (for projects and applications) "
|
||||||
"applications) directory.\n\nYou must run this command with one of either the "
|
"directory.\n\nYou must run this command with one of either the --locale, "
|
||||||
"--locale, --exclude, or --all options."
|
"--exclude, or --all options."
|
||||||
)
|
)
|
||||||
|
|
||||||
translatable_file_class = TranslatableFile
|
translatable_file_class = TranslatableFile
|
||||||
|
@ -226,8 +226,10 @@ class Command(BaseCommand):
|
||||||
"-l",
|
"-l",
|
||||||
default=[],
|
default=[],
|
||||||
action="append",
|
action="append",
|
||||||
help="Creates or updates the message files for the given locale(s) (e.g. pt_BR). "
|
help=(
|
||||||
"Can be used multiple times.",
|
"Creates or updates the message files for the given locale(s) (e.g. "
|
||||||
|
"pt_BR). Can be used multiple times."
|
||||||
|
),
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--exclude",
|
"--exclude",
|
||||||
|
@ -278,7 +280,10 @@ class Command(BaseCommand):
|
||||||
"--no-default-ignore",
|
"--no-default-ignore",
|
||||||
action="store_false",
|
action="store_false",
|
||||||
dest="use_default_ignore_patterns",
|
dest="use_default_ignore_patterns",
|
||||||
help="Don't ignore the common glob-style patterns 'CVS', '.*', '*~' and '*.pyc'.",
|
help=(
|
||||||
|
"Don't ignore the common glob-style patterns 'CVS', '.*', '*~' and "
|
||||||
|
"'*.pyc'."
|
||||||
|
),
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--no-wrap",
|
"--no-wrap",
|
||||||
|
|
|
@ -147,7 +147,8 @@ class Command(BaseCommand):
|
||||||
# hard if there are any and they don't want to merge
|
# hard if there are any and they don't want to merge
|
||||||
conflicts = loader.detect_conflicts()
|
conflicts = loader.detect_conflicts()
|
||||||
|
|
||||||
# If app_labels is specified, filter out conflicting migrations for unspecified apps
|
# If app_labels is specified, filter out conflicting migrations for
|
||||||
|
# unspecified apps.
|
||||||
if app_labels:
|
if app_labels:
|
||||||
conflicts = {
|
conflicts = {
|
||||||
app_label: conflict
|
app_label: conflict
|
||||||
|
|
|
@ -47,7 +47,10 @@ class Command(BaseCommand):
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--database",
|
"--database",
|
||||||
default=DEFAULT_DB_ALIAS,
|
default=DEFAULT_DB_ALIAS,
|
||||||
help='Nominates a database to synchronize. Defaults to the "default" database.',
|
help=(
|
||||||
|
'Nominates a database to synchronize. Defaults to the "default" '
|
||||||
|
"database."
|
||||||
|
),
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--fake",
|
"--fake",
|
||||||
|
@ -57,9 +60,12 @@ class Command(BaseCommand):
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--fake-initial",
|
"--fake-initial",
|
||||||
action="store_true",
|
action="store_true",
|
||||||
help="Detect if tables already exist and fake-apply initial migrations if so. Make sure "
|
help=(
|
||||||
"that the current database schema matches your initial migration before using this "
|
"Detect if tables already exist and fake-apply initial migrations if "
|
||||||
"flag. Django will only check for an existing table name.",
|
"so. Make sure that the current database schema matches your initial "
|
||||||
|
"migration before using this flag. Django will only check for an "
|
||||||
|
"existing table name."
|
||||||
|
),
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--plan",
|
"--plan",
|
||||||
|
@ -313,7 +319,8 @@ class Command(BaseCommand):
|
||||||
if not plan:
|
if not plan:
|
||||||
if self.verbosity >= 1:
|
if self.verbosity >= 1:
|
||||||
self.stdout.write(" No migrations to apply.")
|
self.stdout.write(" No migrations to apply.")
|
||||||
# If there's changes that aren't in migrations yet, tell them how to fix it.
|
# If there's changes that aren't in migrations yet, tell them
|
||||||
|
# how to fix it.
|
||||||
autodetector = MigrationAutodetector(
|
autodetector = MigrationAutodetector(
|
||||||
executor.loader.project_state(),
|
executor.loader.project_state(),
|
||||||
ProjectState.from_apps(apps),
|
ProjectState.from_apps(apps),
|
||||||
|
|
|
@ -7,7 +7,10 @@ from django.utils import timezone
|
||||||
|
|
||||||
class Command(BaseCommand):
|
class Command(BaseCommand):
|
||||||
help = "Sends a test email to the email addresses specified as arguments."
|
help = "Sends a test email to the email addresses specified as arguments."
|
||||||
missing_args_message = "You must specify some email recipients, or pass the --managers or --admin options."
|
missing_args_message = (
|
||||||
|
"You must specify some email recipients, or pass the --managers or --admin "
|
||||||
|
"options."
|
||||||
|
)
|
||||||
|
|
||||||
def add_arguments(self, parser):
|
def add_arguments(self, parser):
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
|
|
|
@ -21,18 +21,27 @@ class Command(BaseCommand):
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--no-startup",
|
"--no-startup",
|
||||||
action="store_true",
|
action="store_true",
|
||||||
help="When using plain Python, ignore the PYTHONSTARTUP environment variable and ~/.pythonrc.py script.",
|
help=(
|
||||||
|
"When using plain Python, ignore the PYTHONSTARTUP environment "
|
||||||
|
"variable and ~/.pythonrc.py script."
|
||||||
|
),
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"-i",
|
"-i",
|
||||||
"--interface",
|
"--interface",
|
||||||
choices=self.shells,
|
choices=self.shells,
|
||||||
help='Specify an interactive interpreter interface. Available options: "ipython", "bpython", and "python"',
|
help=(
|
||||||
|
"Specify an interactive interpreter interface. Available options: "
|
||||||
|
'"ipython", "bpython", and "python"'
|
||||||
|
),
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"-c",
|
"-c",
|
||||||
"--command",
|
"--command",
|
||||||
help="Instead of opening an interactive shell, run a command as Django and exit.",
|
help=(
|
||||||
|
"Instead of opening an interactive shell, run a command as Django and "
|
||||||
|
"exit."
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
def ipython(self, options):
|
def ipython(self, options):
|
||||||
|
|
|
@ -45,9 +45,9 @@ class Command(BaseCommand):
|
||||||
dest="format",
|
dest="format",
|
||||||
const="plan",
|
const="plan",
|
||||||
help=(
|
help=(
|
||||||
"Shows all migrations in the order they will be applied. "
|
"Shows all migrations in the order they will be applied. With a "
|
||||||
"With a verbosity level of 2 or above all direct migration dependencies "
|
"verbosity level of 2 or above all direct migration dependencies and "
|
||||||
"and reverse dependencies (run_before) will be included."
|
"reverse dependencies (run_before) will be included."
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,10 @@ class Command(BaseCommand):
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--database",
|
"--database",
|
||||||
default=DEFAULT_DB_ALIAS,
|
default=DEFAULT_DB_ALIAS,
|
||||||
help='Nominates a database to print the SQL for. Defaults to the "default" database.',
|
help=(
|
||||||
|
'Nominates a database to print the SQL for. Defaults to the "default" '
|
||||||
|
"database."
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
def handle(self, **options):
|
def handle(self, **options):
|
||||||
|
|
|
@ -19,7 +19,10 @@ class Command(BaseCommand):
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--database",
|
"--database",
|
||||||
default=DEFAULT_DB_ALIAS,
|
default=DEFAULT_DB_ALIAS,
|
||||||
help='Nominates a database to create SQL for. Defaults to the "default" database.',
|
help=(
|
||||||
|
'Nominates a database to create SQL for. Defaults to the "default" '
|
||||||
|
"database."
|
||||||
|
),
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--backwards",
|
"--backwards",
|
||||||
|
@ -55,13 +58,13 @@ class Command(BaseCommand):
|
||||||
migration = loader.get_migration_by_prefix(app_label, migration_name)
|
migration = loader.get_migration_by_prefix(app_label, migration_name)
|
||||||
except AmbiguityError:
|
except AmbiguityError:
|
||||||
raise CommandError(
|
raise CommandError(
|
||||||
"More than one migration matches '%s' in app '%s'. Please be more specific."
|
"More than one migration matches '%s' in app '%s'. Please be more "
|
||||||
% (migration_name, app_label)
|
"specific." % (migration_name, app_label)
|
||||||
)
|
)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
raise CommandError(
|
raise CommandError(
|
||||||
"Cannot find a migration matching '%s' from app '%s'. Is it in INSTALLED_APPS?"
|
"Cannot find a migration matching '%s' from app '%s'. Is it in "
|
||||||
% (migration_name, app_label)
|
"INSTALLED_APPS?" % (migration_name, app_label)
|
||||||
)
|
)
|
||||||
target = (app_label, migration.name)
|
target = (app_label, migration.name)
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,10 @@ class Command(AppCommand):
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--database",
|
"--database",
|
||||||
default=DEFAULT_DB_ALIAS,
|
default=DEFAULT_DB_ALIAS,
|
||||||
help='Nominates a database to print the SQL for. Defaults to the "default" database.',
|
help=(
|
||||||
|
'Nominates a database to print the SQL for. Defaults to the "default" '
|
||||||
|
"database."
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
def handle_app_config(self, app_config, **options):
|
def handle_app_config(self, app_config, **options):
|
||||||
|
|
|
@ -12,7 +12,10 @@ from django.utils.version import get_docs_version
|
||||||
|
|
||||||
|
|
||||||
class Command(BaseCommand):
|
class Command(BaseCommand):
|
||||||
help = "Squashes an existing set of migrations (from first until specified) into a single new one."
|
help = (
|
||||||
|
"Squashes an existing set of migrations (from first until specified) into a "
|
||||||
|
"single new one."
|
||||||
|
)
|
||||||
|
|
||||||
def add_arguments(self, parser):
|
def add_arguments(self, parser):
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
|
@ -22,7 +25,10 @@ class Command(BaseCommand):
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"start_migration_name",
|
"start_migration_name",
|
||||||
nargs="?",
|
nargs="?",
|
||||||
help="Migrations will be squashed starting from and including this migration.",
|
help=(
|
||||||
|
"Migrations will be squashed starting from and including this "
|
||||||
|
"migration."
|
||||||
|
),
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"migration_name",
|
"migration_name",
|
||||||
|
@ -66,7 +72,8 @@ class Command(BaseCommand):
|
||||||
apps.get_app_config(app_label)
|
apps.get_app_config(app_label)
|
||||||
except LookupError as err:
|
except LookupError as err:
|
||||||
raise CommandError(str(err))
|
raise CommandError(str(err))
|
||||||
# Load the current graph state, check the app and migration they asked for exists
|
# Load the current graph state, check the app and migration they asked
|
||||||
|
# for exists.
|
||||||
loader = MigrationLoader(connections[DEFAULT_DB_ALIAS])
|
loader = MigrationLoader(connections[DEFAULT_DB_ALIAS])
|
||||||
if app_label not in loader.migrated_apps:
|
if app_label not in loader.migrated_apps:
|
||||||
raise CommandError(
|
raise CommandError(
|
||||||
|
@ -135,10 +142,9 @@ class Command(BaseCommand):
|
||||||
for smigration in migrations_to_squash:
|
for smigration in migrations_to_squash:
|
||||||
if smigration.replaces:
|
if smigration.replaces:
|
||||||
raise CommandError(
|
raise CommandError(
|
||||||
"You cannot squash squashed migrations! Please transition "
|
"You cannot squash squashed migrations! Please transition it to a "
|
||||||
"it to a normal migration first: "
|
"normal migration first: https://docs.djangoproject.com/en/%s/"
|
||||||
"https://docs.djangoproject.com/en/%s/topics/migrations/#squashing-migrations"
|
"topics/migrations/#squashing-migrations" % get_docs_version()
|
||||||
% get_docs_version()
|
|
||||||
)
|
)
|
||||||
operations.extend(smigration.operations)
|
operations.extend(smigration.operations)
|
||||||
for dependency in smigration.dependencies:
|
for dependency in smigration.dependencies:
|
||||||
|
@ -223,15 +229,18 @@ class Command(BaseCommand):
|
||||||
+ "\n"
|
+ "\n"
|
||||||
" You should commit this migration but leave the old ones in place;\n"
|
" You should commit this migration but leave the old ones in place;\n"
|
||||||
" the new migration will be used for new installs. Once you are sure\n"
|
" the new migration will be used for new installs. Once you are sure\n"
|
||||||
" all instances of the codebase have applied the migrations you squashed,\n"
|
" all instances of the codebase have applied the migrations you "
|
||||||
|
"squashed,\n"
|
||||||
" you can delete them."
|
" you can delete them."
|
||||||
)
|
)
|
||||||
if writer.needs_manual_porting:
|
if writer.needs_manual_porting:
|
||||||
self.stdout.write(
|
self.stdout.write(
|
||||||
self.style.MIGRATE_HEADING("Manual porting required") + "\n"
|
self.style.MIGRATE_HEADING("Manual porting required") + "\n"
|
||||||
" Your migrations contained functions that must be manually copied over,\n"
|
" Your migrations contained functions that must be manually "
|
||||||
|
"copied over,\n"
|
||||||
" as we could not safely copy their implementation.\n"
|
" as we could not safely copy their implementation.\n"
|
||||||
" See the comment at the top of the squashed migration for details."
|
" See the comment at the top of the squashed migration for "
|
||||||
|
"details."
|
||||||
)
|
)
|
||||||
|
|
||||||
def find_migration(self, loader, app_label, name):
|
def find_migration(self, loader, app_label, name):
|
||||||
|
|
|
@ -28,7 +28,10 @@ class Command(BaseCommand):
|
||||||
"args",
|
"args",
|
||||||
metavar="test_label",
|
metavar="test_label",
|
||||||
nargs="*",
|
nargs="*",
|
||||||
help="Module paths to test; can be modulename, modulename.TestCase or modulename.TestCase.test_method",
|
help=(
|
||||||
|
"Module paths to test; can be modulename, modulename.TestCase or "
|
||||||
|
"modulename.TestCase.test_method"
|
||||||
|
),
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--noinput",
|
"--noinput",
|
||||||
|
|
|
@ -174,8 +174,11 @@ class EmailValidator:
|
||||||
message = _("Enter a valid email address.")
|
message = _("Enter a valid email address.")
|
||||||
code = "invalid"
|
code = "invalid"
|
||||||
user_regex = _lazy_re_compile(
|
user_regex = _lazy_re_compile(
|
||||||
r"(^[-!#$%&'*+/=?^_`{}|~0-9A-Z]+(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*\Z" # dot-atom
|
# dot-atom
|
||||||
r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-\011\013\014\016-\177])*"\Z)', # quoted-string
|
r"(^[-!#$%&'*+/=?^_`{}|~0-9A-Z]+(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*\Z"
|
||||||
|
# quoted-string
|
||||||
|
r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-\011\013\014\016-\177])'
|
||||||
|
r'*"\Z)',
|
||||||
re.IGNORECASE,
|
re.IGNORECASE,
|
||||||
)
|
)
|
||||||
domain_regex = _lazy_re_compile(
|
domain_regex = _lazy_re_compile(
|
||||||
|
@ -257,7 +260,8 @@ slug_unicode_re = _lazy_re_compile(r"^[-\w]+\Z")
|
||||||
validate_unicode_slug = RegexValidator(
|
validate_unicode_slug = RegexValidator(
|
||||||
slug_unicode_re,
|
slug_unicode_re,
|
||||||
_(
|
_(
|
||||||
"Enter a valid “slug” consisting of Unicode letters, numbers, underscores, or hyphens."
|
"Enter a valid “slug” consisting of Unicode letters, numbers, underscores, or "
|
||||||
|
"hyphens."
|
||||||
),
|
),
|
||||||
"invalid",
|
"invalid",
|
||||||
)
|
)
|
||||||
|
@ -400,8 +404,10 @@ class MinValueValidator(BaseValidator):
|
||||||
@deconstructible
|
@deconstructible
|
||||||
class MinLengthValidator(BaseValidator):
|
class MinLengthValidator(BaseValidator):
|
||||||
message = ngettext_lazy(
|
message = ngettext_lazy(
|
||||||
"Ensure this value has at least %(limit_value)d character (it has %(show_value)d).",
|
"Ensure this value has at least %(limit_value)d character (it has "
|
||||||
"Ensure this value has at least %(limit_value)d characters (it has %(show_value)d).",
|
"%(show_value)d).",
|
||||||
|
"Ensure this value has at least %(limit_value)d characters (it has "
|
||||||
|
"%(show_value)d).",
|
||||||
"limit_value",
|
"limit_value",
|
||||||
)
|
)
|
||||||
code = "min_length"
|
code = "min_length"
|
||||||
|
@ -416,8 +422,10 @@ class MinLengthValidator(BaseValidator):
|
||||||
@deconstructible
|
@deconstructible
|
||||||
class MaxLengthValidator(BaseValidator):
|
class MaxLengthValidator(BaseValidator):
|
||||||
message = ngettext_lazy(
|
message = ngettext_lazy(
|
||||||
"Ensure this value has at most %(limit_value)d character (it has %(show_value)d).",
|
"Ensure this value has at most %(limit_value)d character (it has "
|
||||||
"Ensure this value has at most %(limit_value)d characters (it has %(show_value)d).",
|
"%(show_value)d).",
|
||||||
|
"Ensure this value has at most %(limit_value)d characters (it has "
|
||||||
|
"%(show_value)d).",
|
||||||
"limit_value",
|
"limit_value",
|
||||||
)
|
)
|
||||||
code = "max_length"
|
code = "max_length"
|
||||||
|
@ -449,8 +457,10 @@ class DecimalValidator:
|
||||||
"max",
|
"max",
|
||||||
),
|
),
|
||||||
"max_whole_digits": ngettext_lazy(
|
"max_whole_digits": ngettext_lazy(
|
||||||
"Ensure that there are no more than %(max)s digit before the decimal point.",
|
"Ensure that there are no more than %(max)s digit before the decimal "
|
||||||
"Ensure that there are no more than %(max)s digits before the decimal point.",
|
"point.",
|
||||||
|
"Ensure that there are no more than %(max)s digits before the decimal "
|
||||||
|
"point.",
|
||||||
"max",
|
"max",
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
|
@ -190,19 +190,22 @@ class BaseDatabaseWrapper:
|
||||||
def get_connection_params(self):
|
def get_connection_params(self):
|
||||||
"""Return a dict of parameters suitable for get_new_connection."""
|
"""Return a dict of parameters suitable for get_new_connection."""
|
||||||
raise NotImplementedError(
|
raise NotImplementedError(
|
||||||
"subclasses of BaseDatabaseWrapper may require a get_connection_params() method"
|
"subclasses of BaseDatabaseWrapper may require a get_connection_params() "
|
||||||
|
"method"
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_new_connection(self, conn_params):
|
def get_new_connection(self, conn_params):
|
||||||
"""Open a connection to the database."""
|
"""Open a connection to the database."""
|
||||||
raise NotImplementedError(
|
raise NotImplementedError(
|
||||||
"subclasses of BaseDatabaseWrapper may require a get_new_connection() method"
|
"subclasses of BaseDatabaseWrapper may require a get_new_connection() "
|
||||||
|
"method"
|
||||||
)
|
)
|
||||||
|
|
||||||
def init_connection_state(self):
|
def init_connection_state(self):
|
||||||
"""Initialize the database connection settings."""
|
"""Initialize the database connection settings."""
|
||||||
raise NotImplementedError(
|
raise NotImplementedError(
|
||||||
"subclasses of BaseDatabaseWrapper may require an init_connection_state() method"
|
"subclasses of BaseDatabaseWrapper may require an init_connection_state() "
|
||||||
|
"method"
|
||||||
)
|
)
|
||||||
|
|
||||||
def create_cursor(self, name=None):
|
def create_cursor(self, name=None):
|
||||||
|
|
|
@ -63,7 +63,8 @@ class BaseDatabaseIntrospection:
|
||||||
views that exist in the database.
|
views that exist in the database.
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError(
|
raise NotImplementedError(
|
||||||
"subclasses of BaseDatabaseIntrospection may require a get_table_list() method"
|
"subclasses of BaseDatabaseIntrospection may require a get_table_list() "
|
||||||
|
"method"
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_table_description(self, cursor, table_name):
|
def get_table_description(self, cursor, table_name):
|
||||||
|
@ -158,7 +159,8 @@ class BaseDatabaseIntrospection:
|
||||||
'name' key can be added if the backend supports named sequences.
|
'name' key can be added if the backend supports named sequences.
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError(
|
raise NotImplementedError(
|
||||||
"subclasses of BaseDatabaseIntrospection may require a get_sequences() method"
|
"subclasses of BaseDatabaseIntrospection may require a get_sequences() "
|
||||||
|
"method"
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_relations(self, cursor, table_name):
|
def get_relations(self, cursor, table_name):
|
||||||
|
@ -200,5 +202,6 @@ class BaseDatabaseIntrospection:
|
||||||
if they don't name constraints of a certain type (e.g. SQLite)
|
if they don't name constraints of a certain type (e.g. SQLite)
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError(
|
raise NotImplementedError(
|
||||||
"subclasses of BaseDatabaseIntrospection may require a get_constraints() method"
|
"subclasses of BaseDatabaseIntrospection may require a get_constraints() "
|
||||||
|
"method"
|
||||||
)
|
)
|
||||||
|
|
|
@ -106,7 +106,8 @@ class BaseDatabaseOperations:
|
||||||
extracts a value from the given date field field_name.
|
extracts a value from the given date field field_name.
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError(
|
raise NotImplementedError(
|
||||||
"subclasses of BaseDatabaseOperations may require a date_extract_sql() method"
|
"subclasses of BaseDatabaseOperations may require a date_extract_sql() "
|
||||||
|
"method"
|
||||||
)
|
)
|
||||||
|
|
||||||
def date_trunc_sql(self, lookup_type, field_name, tzname=None):
|
def date_trunc_sql(self, lookup_type, field_name, tzname=None):
|
||||||
|
@ -119,7 +120,8 @@ class BaseDatabaseOperations:
|
||||||
timezone.
|
timezone.
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError(
|
raise NotImplementedError(
|
||||||
"subclasses of BaseDatabaseOperations may require a date_trunc_sql() method."
|
"subclasses of BaseDatabaseOperations may require a date_trunc_sql() "
|
||||||
|
"method."
|
||||||
)
|
)
|
||||||
|
|
||||||
def datetime_cast_date_sql(self, field_name, tzname):
|
def datetime_cast_date_sql(self, field_name, tzname):
|
||||||
|
@ -136,7 +138,8 @@ class BaseDatabaseOperations:
|
||||||
Return the SQL to cast a datetime value to time value.
|
Return the SQL to cast a datetime value to time value.
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError(
|
raise NotImplementedError(
|
||||||
"subclasses of BaseDatabaseOperations may require a datetime_cast_time_sql() method"
|
"subclasses of BaseDatabaseOperations may require a "
|
||||||
|
"datetime_cast_time_sql() method"
|
||||||
)
|
)
|
||||||
|
|
||||||
def datetime_extract_sql(self, lookup_type, field_name, tzname):
|
def datetime_extract_sql(self, lookup_type, field_name, tzname):
|
||||||
|
@ -146,7 +149,8 @@ class BaseDatabaseOperations:
|
||||||
datetime field field_name.
|
datetime field field_name.
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError(
|
raise NotImplementedError(
|
||||||
"subclasses of BaseDatabaseOperations may require a datetime_extract_sql() method"
|
"subclasses of BaseDatabaseOperations may require a datetime_extract_sql() "
|
||||||
|
"method"
|
||||||
)
|
)
|
||||||
|
|
||||||
def datetime_trunc_sql(self, lookup_type, field_name, tzname):
|
def datetime_trunc_sql(self, lookup_type, field_name, tzname):
|
||||||
|
@ -156,7 +160,8 @@ class BaseDatabaseOperations:
|
||||||
field_name to a datetime object with only the given specificity.
|
field_name to a datetime object with only the given specificity.
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError(
|
raise NotImplementedError(
|
||||||
"subclasses of BaseDatabaseOperations may require a datetime_trunc_sql() method"
|
"subclasses of BaseDatabaseOperations may require a datetime_trunc_sql() "
|
||||||
|
"method"
|
||||||
)
|
)
|
||||||
|
|
||||||
def time_trunc_sql(self, lookup_type, field_name, tzname=None):
|
def time_trunc_sql(self, lookup_type, field_name, tzname=None):
|
||||||
|
@ -727,9 +732,9 @@ class BaseDatabaseOperations:
|
||||||
|
|
||||||
def window_frame_range_start_end(self, start=None, end=None):
|
def window_frame_range_start_end(self, start=None, end=None):
|
||||||
start_, end_ = self.window_frame_rows_start_end(start, end)
|
start_, end_ = self.window_frame_rows_start_end(start, end)
|
||||||
if (
|
features = self.connection.features
|
||||||
self.connection.features.only_supports_unbounded_with_preceding_and_following
|
if features.only_supports_unbounded_with_preceding_and_following and (
|
||||||
and ((start and start < 0) or (end and end > 0))
|
(start and start < 0) or (end and end > 0)
|
||||||
):
|
):
|
||||||
raise NotSupportedError(
|
raise NotSupportedError(
|
||||||
"%s only supports UNBOUNDED together with PRECEDING and "
|
"%s only supports UNBOUNDED together with PRECEDING and "
|
||||||
|
|
|
@ -104,7 +104,10 @@ class BaseDatabaseSchemaEditor:
|
||||||
sql_create_check = "ALTER TABLE %(table)s ADD CONSTRAINT %(name)s CHECK (%(check)s)"
|
sql_create_check = "ALTER TABLE %(table)s ADD CONSTRAINT %(name)s CHECK (%(check)s)"
|
||||||
sql_delete_check = sql_delete_constraint
|
sql_delete_check = sql_delete_constraint
|
||||||
|
|
||||||
sql_create_unique = "ALTER TABLE %(table)s ADD CONSTRAINT %(name)s UNIQUE (%(columns)s)%(deferrable)s"
|
sql_create_unique = (
|
||||||
|
"ALTER TABLE %(table)s ADD CONSTRAINT %(name)s "
|
||||||
|
"UNIQUE (%(columns)s)%(deferrable)s"
|
||||||
|
)
|
||||||
sql_delete_unique = sql_delete_constraint
|
sql_delete_unique = sql_delete_constraint
|
||||||
|
|
||||||
sql_create_fk = (
|
sql_create_fk = (
|
||||||
|
@ -115,8 +118,14 @@ class BaseDatabaseSchemaEditor:
|
||||||
sql_create_column_inline_fk = None
|
sql_create_column_inline_fk = None
|
||||||
sql_delete_fk = sql_delete_constraint
|
sql_delete_fk = sql_delete_constraint
|
||||||
|
|
||||||
sql_create_index = "CREATE INDEX %(name)s ON %(table)s (%(columns)s)%(include)s%(extra)s%(condition)s"
|
sql_create_index = (
|
||||||
sql_create_unique_index = "CREATE UNIQUE INDEX %(name)s ON %(table)s (%(columns)s)%(include)s%(condition)s"
|
"CREATE INDEX %(name)s ON %(table)s "
|
||||||
|
"(%(columns)s)%(include)s%(extra)s%(condition)s"
|
||||||
|
)
|
||||||
|
sql_create_unique_index = (
|
||||||
|
"CREATE UNIQUE INDEX %(name)s ON %(table)s "
|
||||||
|
"(%(columns)s)%(include)s%(condition)s"
|
||||||
|
)
|
||||||
sql_delete_index = "DROP INDEX %(name)s"
|
sql_delete_index = "DROP INDEX %(name)s"
|
||||||
|
|
||||||
sql_create_pk = (
|
sql_create_pk = (
|
||||||
|
@ -418,10 +427,12 @@ class BaseDatabaseSchemaEditor:
|
||||||
the given `model`.
|
the given `model`.
|
||||||
"""
|
"""
|
||||||
sql, params = self.table_sql(model)
|
sql, params = self.table_sql(model)
|
||||||
# Prevent using [] as params, in the case a literal '%' is used in the definition
|
# Prevent using [] as params, in the case a literal '%' is used in the
|
||||||
|
# definition.
|
||||||
self.execute(sql, params or None)
|
self.execute(sql, params or None)
|
||||||
|
|
||||||
# Add any field index and index_together's (deferred as SQLite _remake_table needs it)
|
# Add any field index and index_together's (deferred as SQLite
|
||||||
|
# _remake_table needs it).
|
||||||
self.deferred_sql.extend(self._model_indexes_sql(model))
|
self.deferred_sql.extend(self._model_indexes_sql(model))
|
||||||
|
|
||||||
# Make M2M tables
|
# Make M2M tables
|
||||||
|
@ -1190,8 +1201,9 @@ class BaseDatabaseSchemaEditor:
|
||||||
# Repoint the FK to the other side
|
# Repoint the FK to the other side
|
||||||
self.alter_field(
|
self.alter_field(
|
||||||
new_field.remote_field.through,
|
new_field.remote_field.through,
|
||||||
# We need the field that points to the target model, so we can tell alter_field to change it -
|
# The field that points to the target model is needed, so we can
|
||||||
# this is m2m_reverse_field_name() (as opposed to m2m_field_name, which points to our model)
|
# tell alter_field to change it - this is m2m_reverse_field_name()
|
||||||
|
# (as opposed to m2m_field_name(), which points to our model).
|
||||||
old_field.remote_field.through._meta.get_field(
|
old_field.remote_field.through._meta.get_field(
|
||||||
old_field.m2m_reverse_field_name()
|
old_field.m2m_reverse_field_name()
|
||||||
),
|
),
|
||||||
|
|
|
@ -349,9 +349,9 @@ class DatabaseWrapper(BaseDatabaseWrapper):
|
||||||
)
|
)
|
||||||
for bad_row in cursor.fetchall():
|
for bad_row in cursor.fetchall():
|
||||||
raise IntegrityError(
|
raise IntegrityError(
|
||||||
"The row in table '%s' with primary key '%s' has an invalid "
|
"The row in table '%s' with primary key '%s' has an "
|
||||||
"foreign key: %s.%s contains a value '%s' that does not "
|
"invalid foreign key: %s.%s contains a value '%s' that "
|
||||||
"have a corresponding value in %s.%s."
|
"does not have a corresponding value in %s.%s."
|
||||||
% (
|
% (
|
||||||
table_name,
|
table_name,
|
||||||
bad_row[0],
|
bad_row[0],
|
||||||
|
|
|
@ -69,8 +69,10 @@ class DatabaseFeatures(BaseDatabaseFeatures):
|
||||||
def django_test_skips(self):
|
def django_test_skips(self):
|
||||||
skips = {
|
skips = {
|
||||||
"This doesn't work on MySQL.": {
|
"This doesn't work on MySQL.": {
|
||||||
"db_functions.comparison.test_greatest.GreatestTests.test_coalesce_workaround",
|
"db_functions.comparison.test_greatest.GreatestTests."
|
||||||
"db_functions.comparison.test_least.LeastTests.test_coalesce_workaround",
|
"test_coalesce_workaround",
|
||||||
|
"db_functions.comparison.test_least.LeastTests."
|
||||||
|
"test_coalesce_workaround",
|
||||||
},
|
},
|
||||||
"Running on MySQL requires utf8mb4 encoding (#18392).": {
|
"Running on MySQL requires utf8mb4 encoding (#18392).": {
|
||||||
"model_fields.test_textfield.TextFieldTests.test_emoji",
|
"model_fields.test_textfield.TextFieldTests.test_emoji",
|
||||||
|
@ -90,8 +92,10 @@ class DatabaseFeatures(BaseDatabaseFeatures):
|
||||||
{
|
{
|
||||||
"GROUP BY optimization does not work properly when "
|
"GROUP BY optimization does not work properly when "
|
||||||
"ONLY_FULL_GROUP_BY mode is enabled on MySQL, see #31331.": {
|
"ONLY_FULL_GROUP_BY mode is enabled on MySQL, see #31331.": {
|
||||||
"aggregation.tests.AggregateTestCase.test_aggregation_subquery_annotation_multivalued",
|
"aggregation.tests.AggregateTestCase."
|
||||||
"annotations.tests.NonAggregateAnnotationTestCase.test_annotation_aggregate_with_m2o",
|
"test_aggregation_subquery_annotation_multivalued",
|
||||||
|
"annotations.tests.NonAggregateAnnotationTestCase."
|
||||||
|
"test_annotation_aggregate_with_m2o",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -100,13 +104,19 @@ class DatabaseFeatures(BaseDatabaseFeatures):
|
||||||
):
|
):
|
||||||
skips.update(
|
skips.update(
|
||||||
{
|
{
|
||||||
"Casting to datetime/time is not supported by MySQL < 8.0. (#30224)": {
|
"Casting to datetime/time is not supported by MySQL < 8.0. "
|
||||||
"aggregation.tests.AggregateTestCase.test_aggregation_default_using_time_from_python",
|
"(#30224)": {
|
||||||
"aggregation.tests.AggregateTestCase.test_aggregation_default_using_datetime_from_python",
|
"aggregation.tests.AggregateTestCase."
|
||||||
|
"test_aggregation_default_using_time_from_python",
|
||||||
|
"aggregation.tests.AggregateTestCase."
|
||||||
|
"test_aggregation_default_using_datetime_from_python",
|
||||||
},
|
},
|
||||||
"MySQL < 8.0 returns string type instead of datetime/time. (#30224)": {
|
"MySQL < 8.0 returns string type instead of datetime/time. "
|
||||||
"aggregation.tests.AggregateTestCase.test_aggregation_default_using_time_from_database",
|
"(#30224)": {
|
||||||
"aggregation.tests.AggregateTestCase.test_aggregation_default_using_datetime_from_database",
|
"aggregation.tests.AggregateTestCase."
|
||||||
|
"test_aggregation_default_using_time_from_database",
|
||||||
|
"aggregation.tests.AggregateTestCase."
|
||||||
|
"test_aggregation_default_using_datetime_from_database",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -118,7 +128,8 @@ class DatabaseFeatures(BaseDatabaseFeatures):
|
||||||
skips.update(
|
skips.update(
|
||||||
{
|
{
|
||||||
"https://jira.mariadb.org/browse/MDEV-19598": {
|
"https://jira.mariadb.org/browse/MDEV-19598": {
|
||||||
"schema.tests.SchemaTests.test_alter_not_unique_field_to_primary_key",
|
"schema.tests.SchemaTests."
|
||||||
|
"test_alter_not_unique_field_to_primary_key",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -130,7 +141,8 @@ class DatabaseFeatures(BaseDatabaseFeatures):
|
||||||
skips.update(
|
skips.update(
|
||||||
{
|
{
|
||||||
"https://jira.mariadb.org/browse/MDEV-22775": {
|
"https://jira.mariadb.org/browse/MDEV-22775": {
|
||||||
"schema.tests.SchemaTests.test_alter_pk_with_self_referential_field",
|
"schema.tests.SchemaTests."
|
||||||
|
"test_alter_pk_with_self_referential_field",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
@ -92,7 +92,8 @@ class DatabaseIntrospection(BaseDatabaseIntrospection):
|
||||||
FROM information_schema.check_constraints AS c
|
FROM information_schema.check_constraints AS c
|
||||||
WHERE
|
WHERE
|
||||||
c.table_name = %s AND
|
c.table_name = %s AND
|
||||||
LOWER(c.check_clause) = 'json_valid(`' + LOWER(c.constraint_name) + '`)' AND
|
LOWER(c.check_clause) =
|
||||||
|
'json_valid(`' + LOWER(c.constraint_name) + '`)' AND
|
||||||
c.constraint_schema = DATABASE()
|
c.constraint_schema = DATABASE()
|
||||||
""",
|
""",
|
||||||
[table_name],
|
[table_name],
|
||||||
|
|
|
@ -69,7 +69,8 @@ class DatabaseOperations(BaseDatabaseOperations):
|
||||||
return "CAST(DATE_FORMAT(%s, '%s') AS DATE)" % (field_name, format_str)
|
return "CAST(DATE_FORMAT(%s, '%s') AS DATE)" % (field_name, format_str)
|
||||||
elif lookup_type == "quarter":
|
elif lookup_type == "quarter":
|
||||||
return (
|
return (
|
||||||
"MAKEDATE(YEAR(%s), 1) + INTERVAL QUARTER(%s) QUARTER - INTERVAL 1 QUARTER"
|
"MAKEDATE(YEAR(%s), 1) + "
|
||||||
|
"INTERVAL QUARTER(%s) QUARTER - INTERVAL 1 QUARTER"
|
||||||
% (field_name, field_name)
|
% (field_name, field_name)
|
||||||
)
|
)
|
||||||
elif lookup_type == "week":
|
elif lookup_type == "week":
|
||||||
|
@ -266,7 +267,8 @@ class DatabaseOperations(BaseDatabaseOperations):
|
||||||
value = timezone.make_naive(value, self.connection.timezone)
|
value = timezone.make_naive(value, self.connection.timezone)
|
||||||
else:
|
else:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
"MySQL backend does not support timezone-aware datetimes when USE_TZ is False."
|
"MySQL backend does not support timezone-aware datetimes when "
|
||||||
|
"USE_TZ is False."
|
||||||
)
|
)
|
||||||
return str(value)
|
return str(value)
|
||||||
|
|
||||||
|
@ -347,7 +349,10 @@ class DatabaseOperations(BaseDatabaseOperations):
|
||||||
if self.connection.mysql_is_mariadb:
|
if self.connection.mysql_is_mariadb:
|
||||||
# MariaDB includes the microsecond component in TIME_TO_SEC as
|
# MariaDB includes the microsecond component in TIME_TO_SEC as
|
||||||
# a decimal. MySQL returns an integer without microseconds.
|
# a decimal. MySQL returns an integer without microseconds.
|
||||||
return "CAST((TIME_TO_SEC(%(lhs)s) - TIME_TO_SEC(%(rhs)s)) * 1000000 AS SIGNED)" % {
|
return (
|
||||||
|
"CAST((TIME_TO_SEC(%(lhs)s) - TIME_TO_SEC(%(rhs)s)) "
|
||||||
|
"* 1000000 AS SIGNED)"
|
||||||
|
) % {
|
||||||
"lhs": lhs_sql,
|
"lhs": lhs_sql,
|
||||||
"rhs": rhs_sql,
|
"rhs": rhs_sql,
|
||||||
}, (
|
}, (
|
||||||
|
|
|
@ -22,7 +22,8 @@ class DatabaseValidation(BaseDatabaseValidation):
|
||||||
"%s, such as data truncation upon insertion, by "
|
"%s, such as data truncation upon insertion, by "
|
||||||
"escalating warnings into errors. It is strongly "
|
"escalating warnings into errors. It is strongly "
|
||||||
"recommended you activate it. See: "
|
"recommended you activate it. See: "
|
||||||
"https://docs.djangoproject.com/en/%s/ref/databases/#mysql-sql-mode"
|
"https://docs.djangoproject.com/en/%s/ref/databases/"
|
||||||
|
"#mysql-sql-mode"
|
||||||
% (
|
% (
|
||||||
self.connection.display_name,
|
self.connection.display_name,
|
||||||
self.connection.display_name,
|
self.connection.display_name,
|
||||||
|
|
|
@ -158,16 +158,31 @@ class DatabaseWrapper(BaseDatabaseWrapper):
|
||||||
_standard_operators = {
|
_standard_operators = {
|
||||||
"exact": "= %s",
|
"exact": "= %s",
|
||||||
"iexact": "= UPPER(%s)",
|
"iexact": "= UPPER(%s)",
|
||||||
"contains": "LIKE TRANSLATE(%s USING NCHAR_CS) ESCAPE TRANSLATE('\\' USING NCHAR_CS)",
|
"contains": (
|
||||||
"icontains": "LIKE UPPER(TRANSLATE(%s USING NCHAR_CS)) ESCAPE TRANSLATE('\\' USING NCHAR_CS)",
|
"LIKE TRANSLATE(%s USING NCHAR_CS) ESCAPE TRANSLATE('\\' USING NCHAR_CS)"
|
||||||
|
),
|
||||||
|
"icontains": (
|
||||||
|
"LIKE UPPER(TRANSLATE(%s USING NCHAR_CS)) "
|
||||||
|
"ESCAPE TRANSLATE('\\' USING NCHAR_CS)"
|
||||||
|
),
|
||||||
"gt": "> %s",
|
"gt": "> %s",
|
||||||
"gte": ">= %s",
|
"gte": ">= %s",
|
||||||
"lt": "< %s",
|
"lt": "< %s",
|
||||||
"lte": "<= %s",
|
"lte": "<= %s",
|
||||||
"startswith": "LIKE TRANSLATE(%s USING NCHAR_CS) ESCAPE TRANSLATE('\\' USING NCHAR_CS)",
|
"startswith": (
|
||||||
"endswith": "LIKE TRANSLATE(%s USING NCHAR_CS) ESCAPE TRANSLATE('\\' USING NCHAR_CS)",
|
"LIKE TRANSLATE(%s USING NCHAR_CS) ESCAPE TRANSLATE('\\' USING NCHAR_CS)"
|
||||||
"istartswith": "LIKE UPPER(TRANSLATE(%s USING NCHAR_CS)) ESCAPE TRANSLATE('\\' USING NCHAR_CS)",
|
),
|
||||||
"iendswith": "LIKE UPPER(TRANSLATE(%s USING NCHAR_CS)) ESCAPE TRANSLATE('\\' USING NCHAR_CS)",
|
"endswith": (
|
||||||
|
"LIKE TRANSLATE(%s USING NCHAR_CS) ESCAPE TRANSLATE('\\' USING NCHAR_CS)"
|
||||||
|
),
|
||||||
|
"istartswith": (
|
||||||
|
"LIKE UPPER(TRANSLATE(%s USING NCHAR_CS)) "
|
||||||
|
"ESCAPE TRANSLATE('\\' USING NCHAR_CS)"
|
||||||
|
),
|
||||||
|
"iendswith": (
|
||||||
|
"LIKE UPPER(TRANSLATE(%s USING NCHAR_CS)) "
|
||||||
|
"ESCAPE TRANSLATE('\\' USING NCHAR_CS)"
|
||||||
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
_likec_operators = {
|
_likec_operators = {
|
||||||
|
|
|
@ -61,7 +61,8 @@ class DatabaseCreation(BaseDatabaseCreation):
|
||||||
cursor, parameters, verbosity, autoclobber
|
cursor, parameters, verbosity, autoclobber
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
# Ran into a database error that isn't about leftover objects in the tablespace
|
# Ran into a database error that isn't about
|
||||||
|
# leftover objects in the tablespace.
|
||||||
self.log(
|
self.log(
|
||||||
"Got an error destroying the old test database: %s"
|
"Got an error destroying the old test database: %s"
|
||||||
% e
|
% e
|
||||||
|
@ -117,7 +118,8 @@ class DatabaseCreation(BaseDatabaseCreation):
|
||||||
else:
|
else:
|
||||||
self.log("Tests cancelled.")
|
self.log("Tests cancelled.")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
self._maindb_connection.close() # done with main user -- test user and tablespaces created
|
# Done with main user -- test user and tablespaces created.
|
||||||
|
self._maindb_connection.close()
|
||||||
self._switch_to_test_user(parameters)
|
self._switch_to_test_user(parameters)
|
||||||
return self.connection.settings_dict["NAME"]
|
return self.connection.settings_dict["NAME"]
|
||||||
|
|
||||||
|
@ -160,8 +162,8 @@ class DatabaseCreation(BaseDatabaseCreation):
|
||||||
# There are objects in the test tablespace which prevent dropping it
|
# There are objects in the test tablespace which prevent dropping it
|
||||||
# The easy fix is to drop the test user -- but are we allowed to do so?
|
# The easy fix is to drop the test user -- but are we allowed to do so?
|
||||||
self.log(
|
self.log(
|
||||||
"There are objects in the old test database which prevent its destruction.\n"
|
"There are objects in the old test database which prevent its destruction."
|
||||||
"If they belong to the test user, deleting the user will allow the test "
|
"\nIf they belong to the test user, deleting the user will allow the test "
|
||||||
"database to be recreated.\n"
|
"database to be recreated.\n"
|
||||||
"Otherwise, you will need to find and remove each of these objects, "
|
"Otherwise, you will need to find and remove each of these objects, "
|
||||||
"or use a different tablespace.\n"
|
"or use a different tablespace.\n"
|
||||||
|
@ -301,8 +303,10 @@ class DatabaseCreation(BaseDatabaseCreation):
|
||||||
if verbosity >= 2:
|
if verbosity >= 2:
|
||||||
self.log("_execute_test_db_destruction(): dbname=%s" % parameters["user"])
|
self.log("_execute_test_db_destruction(): dbname=%s" % parameters["user"])
|
||||||
statements = [
|
statements = [
|
||||||
"DROP TABLESPACE %(tblspace)s INCLUDING CONTENTS AND DATAFILES CASCADE CONSTRAINTS",
|
"DROP TABLESPACE %(tblspace)s "
|
||||||
"DROP TABLESPACE %(tblspace_temp)s INCLUDING CONTENTS AND DATAFILES CASCADE CONSTRAINTS",
|
"INCLUDING CONTENTS AND DATAFILES CASCADE CONSTRAINTS",
|
||||||
|
"DROP TABLESPACE %(tblspace_temp)s "
|
||||||
|
"INCLUDING CONTENTS AND DATAFILES CASCADE CONSTRAINTS",
|
||||||
]
|
]
|
||||||
self._execute_statements(cursor, statements, parameters, verbosity)
|
self._execute_statements(cursor, statements, parameters, verbosity)
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,8 @@ class DatabaseFeatures(BaseDatabaseFeatures):
|
||||||
requires_literal_defaults = True
|
requires_literal_defaults = True
|
||||||
closed_cursor_error_class = InterfaceError
|
closed_cursor_error_class = InterfaceError
|
||||||
bare_select_suffix = " FROM DUAL"
|
bare_select_suffix = " FROM DUAL"
|
||||||
# select for update with limit can be achieved on Oracle, but not with the current backend.
|
# Select for update with limit can be achieved on Oracle, but not with the
|
||||||
|
# current backend.
|
||||||
supports_select_for_update_with_limit = False
|
supports_select_for_update_with_limit = False
|
||||||
supports_temporal_subtraction = True
|
supports_temporal_subtraction = True
|
||||||
# Oracle doesn't ignore quoted identifiers case but the current backend
|
# Oracle doesn't ignore quoted identifiers case but the current backend
|
||||||
|
@ -79,13 +80,16 @@ class DatabaseFeatures(BaseDatabaseFeatures):
|
||||||
},
|
},
|
||||||
"Oracle doesn't correctly calculate ISO 8601 week numbering before "
|
"Oracle doesn't correctly calculate ISO 8601 week numbering before "
|
||||||
"1583 (the Gregorian calendar was introduced in 1582).": {
|
"1583 (the Gregorian calendar was introduced in 1582).": {
|
||||||
"db_functions.datetime.test_extract_trunc.DateFunctionTests.test_trunc_week_before_1000",
|
"db_functions.datetime.test_extract_trunc.DateFunctionTests."
|
||||||
"db_functions.datetime.test_extract_trunc.DateFunctionWithTimeZoneTests.test_trunc_week_before_1000",
|
"test_trunc_week_before_1000",
|
||||||
|
"db_functions.datetime.test_extract_trunc.DateFunctionWithTimeZoneTests."
|
||||||
|
"test_trunc_week_before_1000",
|
||||||
},
|
},
|
||||||
"Oracle doesn't support bitwise XOR.": {
|
"Oracle doesn't support bitwise XOR.": {
|
||||||
"expressions.tests.ExpressionOperatorTests.test_lefthand_bitwise_xor",
|
"expressions.tests.ExpressionOperatorTests.test_lefthand_bitwise_xor",
|
||||||
"expressions.tests.ExpressionOperatorTests.test_lefthand_bitwise_xor_null",
|
"expressions.tests.ExpressionOperatorTests.test_lefthand_bitwise_xor_null",
|
||||||
"expressions.tests.ExpressionOperatorTests.test_lefthand_bitwise_xor_right_null",
|
"expressions.tests.ExpressionOperatorTests."
|
||||||
|
"test_lefthand_bitwise_xor_right_null",
|
||||||
},
|
},
|
||||||
"Oracle requires ORDER BY in row_number, ANSI:SQL doesn't.": {
|
"Oracle requires ORDER BY in row_number, ANSI:SQL doesn't.": {
|
||||||
"expressions_window.tests.WindowFunctionTests.test_row_number_no_ordering",
|
"expressions_window.tests.WindowFunctionTests.test_row_number_no_ordering",
|
||||||
|
@ -97,7 +101,8 @@ class DatabaseFeatures(BaseDatabaseFeatures):
|
||||||
django_test_expected_failures = {
|
django_test_expected_failures = {
|
||||||
# A bug in Django/cx_Oracle with respect to string handling (#23843).
|
# A bug in Django/cx_Oracle with respect to string handling (#23843).
|
||||||
"annotations.tests.NonAggregateAnnotationTestCase.test_custom_functions",
|
"annotations.tests.NonAggregateAnnotationTestCase.test_custom_functions",
|
||||||
"annotations.tests.NonAggregateAnnotationTestCase.test_custom_functions_can_ref_other_functions",
|
"annotations.tests.NonAggregateAnnotationTestCase."
|
||||||
|
"test_custom_functions_can_ref_other_functions",
|
||||||
}
|
}
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
|
|
|
@ -147,7 +147,14 @@ class DatabaseIntrospection(BaseDatabaseIntrospection):
|
||||||
is_autofield,
|
is_autofield,
|
||||||
is_json,
|
is_json,
|
||||||
)
|
)
|
||||||
for column, default, collation, internal_size, is_autofield, is_json in cursor.fetchall()
|
for (
|
||||||
|
column,
|
||||||
|
default,
|
||||||
|
collation,
|
||||||
|
internal_size,
|
||||||
|
is_autofield,
|
||||||
|
is_json,
|
||||||
|
) in cursor.fetchall()
|
||||||
}
|
}
|
||||||
self.cache_bust_counter += 1
|
self.cache_bust_counter += 1
|
||||||
cursor.execute(
|
cursor.execute(
|
||||||
|
@ -271,7 +278,8 @@ class DatabaseIntrospection(BaseDatabaseIntrospection):
|
||||||
"""
|
"""
|
||||||
SELECT
|
SELECT
|
||||||
user_constraints.constraint_name,
|
user_constraints.constraint_name,
|
||||||
LISTAGG(LOWER(cols.column_name), ',') WITHIN GROUP (ORDER BY cols.position),
|
LISTAGG(LOWER(cols.column_name), ',')
|
||||||
|
WITHIN GROUP (ORDER BY cols.position),
|
||||||
CASE user_constraints.constraint_type
|
CASE user_constraints.constraint_type
|
||||||
WHEN 'P' THEN 1
|
WHEN 'P' THEN 1
|
||||||
ELSE 0
|
ELSE 0
|
||||||
|
@ -287,7 +295,8 @@ class DatabaseIntrospection(BaseDatabaseIntrospection):
|
||||||
FROM
|
FROM
|
||||||
user_constraints
|
user_constraints
|
||||||
LEFT OUTER JOIN
|
LEFT OUTER JOIN
|
||||||
user_cons_columns cols ON user_constraints.constraint_name = cols.constraint_name
|
user_cons_columns cols
|
||||||
|
ON user_constraints.constraint_name = cols.constraint_name
|
||||||
WHERE
|
WHERE
|
||||||
user_constraints.constraint_type = ANY('P', 'U', 'C')
|
user_constraints.constraint_type = ANY('P', 'U', 'C')
|
||||||
AND user_constraints.table_name = UPPER(%s)
|
AND user_constraints.table_name = UPPER(%s)
|
||||||
|
@ -310,15 +319,18 @@ class DatabaseIntrospection(BaseDatabaseIntrospection):
|
||||||
"""
|
"""
|
||||||
SELECT
|
SELECT
|
||||||
cons.constraint_name,
|
cons.constraint_name,
|
||||||
LISTAGG(LOWER(cols.column_name), ',') WITHIN GROUP (ORDER BY cols.position),
|
LISTAGG(LOWER(cols.column_name), ',')
|
||||||
|
WITHIN GROUP (ORDER BY cols.position),
|
||||||
LOWER(rcols.table_name),
|
LOWER(rcols.table_name),
|
||||||
LOWER(rcols.column_name)
|
LOWER(rcols.column_name)
|
||||||
FROM
|
FROM
|
||||||
user_constraints cons
|
user_constraints cons
|
||||||
INNER JOIN
|
INNER JOIN
|
||||||
user_cons_columns rcols ON rcols.constraint_name = cons.r_constraint_name AND rcols.position = 1
|
user_cons_columns rcols
|
||||||
|
ON rcols.constraint_name = cons.r_constraint_name AND rcols.position = 1
|
||||||
LEFT OUTER JOIN
|
LEFT OUTER JOIN
|
||||||
user_cons_columns cols ON cons.constraint_name = cols.constraint_name
|
user_cons_columns cols
|
||||||
|
ON cons.constraint_name = cols.constraint_name
|
||||||
WHERE
|
WHERE
|
||||||
cons.constraint_type = 'R' AND
|
cons.constraint_type = 'R' AND
|
||||||
cons.table_name = UPPER(%s)
|
cons.table_name = UPPER(%s)
|
||||||
|
@ -343,7 +355,8 @@ class DatabaseIntrospection(BaseDatabaseIntrospection):
|
||||||
ind.index_name,
|
ind.index_name,
|
||||||
LOWER(ind.index_type),
|
LOWER(ind.index_type),
|
||||||
LOWER(ind.uniqueness),
|
LOWER(ind.uniqueness),
|
||||||
LISTAGG(LOWER(cols.column_name), ',') WITHIN GROUP (ORDER BY cols.column_position),
|
LISTAGG(LOWER(cols.column_name), ',')
|
||||||
|
WITHIN GROUP (ORDER BY cols.column_position),
|
||||||
LISTAGG(cols.descend, ',') WITHIN GROUP (ORDER BY cols.column_position)
|
LISTAGG(cols.descend, ',') WITHIN GROUP (ORDER BY cols.column_position)
|
||||||
FROM
|
FROM
|
||||||
user_ind_columns cols, user_indexes ind
|
user_ind_columns cols, user_indexes ind
|
||||||
|
|
|
@ -399,12 +399,15 @@ END;
|
||||||
user_tables
|
user_tables
|
||||||
JOIN
|
JOIN
|
||||||
user_constraints cons
|
user_constraints cons
|
||||||
ON (user_tables.table_name = cons.table_name AND cons.constraint_type = ANY('P', 'U'))
|
ON (user_tables.table_name = cons.table_name
|
||||||
|
AND cons.constraint_type = ANY('P', 'U'))
|
||||||
LEFT JOIN
|
LEFT JOIN
|
||||||
user_constraints rcons
|
user_constraints rcons
|
||||||
ON (user_tables.table_name = rcons.table_name AND rcons.constraint_type = 'R')
|
ON (user_tables.table_name = rcons.table_name
|
||||||
|
AND rcons.constraint_type = 'R')
|
||||||
START WITH user_tables.table_name = UPPER(%s)
|
START WITH user_tables.table_name = UPPER(%s)
|
||||||
CONNECT BY NOCYCLE PRIOR cons.constraint_name = rcons.r_constraint_name
|
CONNECT BY
|
||||||
|
NOCYCLE PRIOR cons.constraint_name = rcons.r_constraint_name
|
||||||
GROUP BY
|
GROUP BY
|
||||||
user_tables.table_name, rcons.constraint_name
|
user_tables.table_name, rcons.constraint_name
|
||||||
HAVING user_tables.table_name != UPPER(%s)
|
HAVING user_tables.table_name != UPPER(%s)
|
||||||
|
@ -583,7 +586,8 @@ END;
|
||||||
value = timezone.make_naive(value, self.connection.timezone)
|
value = timezone.make_naive(value, self.connection.timezone)
|
||||||
else:
|
else:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
"Oracle backend does not support timezone-aware datetimes when USE_TZ is False."
|
"Oracle backend does not support timezone-aware datetimes when "
|
||||||
|
"USE_TZ is False."
|
||||||
)
|
)
|
||||||
|
|
||||||
return Oracle_datetime.from_datetime(value)
|
return Oracle_datetime.from_datetime(value)
|
||||||
|
|
|
@ -132,10 +132,8 @@ class DatabaseSchemaEditor(BaseDatabaseSchemaEditor):
|
||||||
new_value = "TO_TIMESTAMP(%s, 'YYYY-MM-DD HH24:MI:SS.FF')" % new_value
|
new_value = "TO_TIMESTAMP(%s, 'YYYY-MM-DD HH24:MI:SS.FF')" % new_value
|
||||||
elif new_internal_type == "TimeField":
|
elif new_internal_type == "TimeField":
|
||||||
# TimeField are stored as TIMESTAMP with a 1900-01-01 date part.
|
# TimeField are stored as TIMESTAMP with a 1900-01-01 date part.
|
||||||
new_value = (
|
new_value = "CONCAT('1900-01-01 ', %s)" % new_value
|
||||||
"TO_TIMESTAMP(CONCAT('1900-01-01 ', %s), 'YYYY-MM-DD HH24:MI:SS.FF')"
|
new_value = "TO_TIMESTAMP(%s, 'YYYY-MM-DD HH24:MI:SS.FF')" % new_value
|
||||||
% new_value
|
|
||||||
)
|
|
||||||
# Transfer values across
|
# Transfer values across
|
||||||
self.execute(
|
self.execute(
|
||||||
"UPDATE %s set %s=%s"
|
"UPDATE %s set %s=%s"
|
||||||
|
|
|
@ -67,7 +67,8 @@ class DatabaseFeatures(BaseDatabaseFeatures):
|
||||||
|
|
||||||
django_test_skips = {
|
django_test_skips = {
|
||||||
"opclasses are PostgreSQL only.": {
|
"opclasses are PostgreSQL only.": {
|
||||||
"indexes.tests.SchemaIndexesNotPostgreSQLTests.test_create_index_ignores_opclasses",
|
"indexes.tests.SchemaIndexesNotPostgreSQLTests."
|
||||||
|
"test_create_index_ignores_opclasses",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -50,8 +50,13 @@ class DatabaseIntrospection(BaseDatabaseIntrospection):
|
||||||
"""Return a list of table and view names in the current database."""
|
"""Return a list of table and view names in the current database."""
|
||||||
cursor.execute(
|
cursor.execute(
|
||||||
"""
|
"""
|
||||||
SELECT c.relname,
|
SELECT
|
||||||
CASE WHEN c.relispartition THEN 'p' WHEN c.relkind IN ('m', 'v') THEN 'v' ELSE 't' END
|
c.relname,
|
||||||
|
CASE
|
||||||
|
WHEN c.relispartition THEN 'p'
|
||||||
|
WHEN c.relkind IN ('m', 'v') THEN 'v'
|
||||||
|
ELSE 't'
|
||||||
|
END
|
||||||
FROM pg_catalog.pg_class c
|
FROM pg_catalog.pg_class c
|
||||||
LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
|
LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
|
||||||
WHERE c.relkind IN ('f', 'm', 'p', 'r', 'v')
|
WHERE c.relkind IN ('f', 'm', 'p', 'r', 'v')
|
||||||
|
@ -116,9 +121,15 @@ class DatabaseIntrospection(BaseDatabaseIntrospection):
|
||||||
SELECT s.relname as sequence_name, col.attname
|
SELECT s.relname as sequence_name, col.attname
|
||||||
FROM pg_class s
|
FROM pg_class s
|
||||||
JOIN pg_namespace sn ON sn.oid = s.relnamespace
|
JOIN pg_namespace sn ON sn.oid = s.relnamespace
|
||||||
JOIN pg_depend d ON d.refobjid = s.oid AND d.refclassid = 'pg_class'::regclass
|
JOIN
|
||||||
JOIN pg_attrdef ad ON ad.oid = d.objid AND d.classid = 'pg_attrdef'::regclass
|
pg_depend d ON d.refobjid = s.oid
|
||||||
JOIN pg_attribute col ON col.attrelid = ad.adrelid AND col.attnum = ad.adnum
|
AND d.refclassid = 'pg_class'::regclass
|
||||||
|
JOIN
|
||||||
|
pg_attrdef ad ON ad.oid = d.objid
|
||||||
|
AND d.classid = 'pg_attrdef'::regclass
|
||||||
|
JOIN
|
||||||
|
pg_attribute col ON col.attrelid = ad.adrelid
|
||||||
|
AND col.attnum = ad.adnum
|
||||||
JOIN pg_class tbl ON tbl.oid = ad.adrelid
|
JOIN pg_class tbl ON tbl.oid = ad.adrelid
|
||||||
WHERE s.relkind = 'S'
|
WHERE s.relkind = 'S'
|
||||||
AND d.deptype in ('a', 'n')
|
AND d.deptype in ('a', 'n')
|
||||||
|
@ -143,8 +154,10 @@ class DatabaseIntrospection(BaseDatabaseIntrospection):
|
||||||
FROM pg_constraint con
|
FROM pg_constraint con
|
||||||
LEFT JOIN pg_class c1 ON con.conrelid = c1.oid
|
LEFT JOIN pg_class c1 ON con.conrelid = c1.oid
|
||||||
LEFT JOIN pg_class c2 ON con.confrelid = c2.oid
|
LEFT JOIN pg_class c2 ON con.confrelid = c2.oid
|
||||||
LEFT JOIN pg_attribute a1 ON c1.oid = a1.attrelid AND a1.attnum = con.conkey[1]
|
LEFT JOIN
|
||||||
LEFT JOIN pg_attribute a2 ON c2.oid = a2.attrelid AND a2.attnum = con.confkey[1]
|
pg_attribute a1 ON c1.oid = a1.attrelid AND a1.attnum = con.conkey[1]
|
||||||
|
LEFT JOIN
|
||||||
|
pg_attribute a2 ON c2.oid = a2.attrelid AND a2.attnum = con.confkey[1]
|
||||||
WHERE
|
WHERE
|
||||||
c1.relname = %s AND
|
c1.relname = %s AND
|
||||||
con.contype = 'f' AND
|
con.contype = 'f' AND
|
||||||
|
@ -203,8 +216,14 @@ class DatabaseIntrospection(BaseDatabaseIntrospection):
|
||||||
cursor.execute(
|
cursor.execute(
|
||||||
"""
|
"""
|
||||||
SELECT
|
SELECT
|
||||||
indexname, array_agg(attname ORDER BY arridx), indisunique, indisprimary,
|
indexname,
|
||||||
array_agg(ordering ORDER BY arridx), amname, exprdef, s2.attoptions
|
array_agg(attname ORDER BY arridx),
|
||||||
|
indisunique,
|
||||||
|
indisprimary,
|
||||||
|
array_agg(ordering ORDER BY arridx),
|
||||||
|
amname,
|
||||||
|
exprdef,
|
||||||
|
s2.attoptions
|
||||||
FROM (
|
FROM (
|
||||||
SELECT
|
SELECT
|
||||||
c2.relname as indexname, idx.*, attr.attname, am.amname,
|
c2.relname as indexname, idx.*, attr.attname, am.amname,
|
||||||
|
@ -221,12 +240,16 @@ class DatabaseIntrospection(BaseDatabaseIntrospection):
|
||||||
c2.reloptions as attoptions
|
c2.reloptions as attoptions
|
||||||
FROM (
|
FROM (
|
||||||
SELECT *
|
SELECT *
|
||||||
FROM pg_index i, unnest(i.indkey, i.indoption) WITH ORDINALITY koi(key, option, arridx)
|
FROM
|
||||||
|
pg_index i,
|
||||||
|
unnest(i.indkey, i.indoption)
|
||||||
|
WITH ORDINALITY koi(key, option, arridx)
|
||||||
) idx
|
) idx
|
||||||
LEFT JOIN pg_class c ON idx.indrelid = c.oid
|
LEFT JOIN pg_class c ON idx.indrelid = c.oid
|
||||||
LEFT JOIN pg_class c2 ON idx.indexrelid = c2.oid
|
LEFT JOIN pg_class c2 ON idx.indexrelid = c2.oid
|
||||||
LEFT JOIN pg_am am ON c2.relam = am.oid
|
LEFT JOIN pg_am am ON c2.relam = am.oid
|
||||||
LEFT JOIN pg_attribute attr ON attr.attrelid = c.oid AND attr.attnum = idx.key
|
LEFT JOIN
|
||||||
|
pg_attribute attr ON attr.attrelid = c.oid AND attr.attnum = idx.key
|
||||||
WHERE c.relname = %s AND pg_catalog.pg_table_is_visible(c.oid)
|
WHERE c.relname = %s AND pg_catalog.pg_table_is_visible(c.oid)
|
||||||
) s2
|
) s2
|
||||||
GROUP BY indexname, indisunique, indisprimary, amname, exprdef, attoptions;
|
GROUP BY indexname, indisunique, indisprimary, amname, exprdef, attoptions;
|
||||||
|
|
|
@ -187,11 +187,12 @@ class DatabaseOperations(BaseDatabaseOperations):
|
||||||
output = []
|
output = []
|
||||||
qn = self.quote_name
|
qn = self.quote_name
|
||||||
for model in model_list:
|
for model in model_list:
|
||||||
# Use `coalesce` to set the sequence for each model to the max pk value if there are records,
|
# Use `coalesce` to set the sequence for each model to the max pk
|
||||||
# or 1 if there are none. Set the `is_called` property (the third argument to `setval`) to true
|
# value if there are records, or 1 if there are none. Set the
|
||||||
# if there are records (as the max pk value is already in use), otherwise set it to false.
|
# `is_called` property (the third argument to `setval`) to true if
|
||||||
# Use pg_get_serial_sequence to get the underlying sequence name from the table name
|
# there are records (as the max pk value is already in use),
|
||||||
# and column name (available since PostgreSQL 8)
|
# otherwise set it to false. Use pg_get_serial_sequence to get the
|
||||||
|
# underlying sequence name from the table name and column name.
|
||||||
|
|
||||||
for f in model._meta.local_fields:
|
for f in model._meta.local_fields:
|
||||||
if isinstance(f, models.AutoField):
|
if isinstance(f, models.AutoField):
|
||||||
|
@ -209,7 +210,9 @@ class DatabaseOperations(BaseDatabaseOperations):
|
||||||
style.SQL_TABLE(qn(model._meta.db_table)),
|
style.SQL_TABLE(qn(model._meta.db_table)),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
break # Only one AutoField is allowed per model, so don't bother continuing.
|
# Only one AutoField is allowed per model, so don't bother
|
||||||
|
# continuing.
|
||||||
|
break
|
||||||
return output
|
return output
|
||||||
|
|
||||||
def prep_for_iexact_query(self, x):
|
def prep_for_iexact_query(self, x):
|
||||||
|
|
|
@ -33,8 +33,10 @@ class DatabaseSchemaEditor(BaseDatabaseSchemaEditor):
|
||||||
)
|
)
|
||||||
# Setting the constraint to IMMEDIATE runs any deferred checks to allow
|
# Setting the constraint to IMMEDIATE runs any deferred checks to allow
|
||||||
# dropping it in the same transaction.
|
# dropping it in the same transaction.
|
||||||
sql_delete_fk = "SET CONSTRAINTS %(name)s IMMEDIATE; ALTER TABLE %(table)s DROP CONSTRAINT %(name)s"
|
sql_delete_fk = (
|
||||||
|
"SET CONSTRAINTS %(name)s IMMEDIATE; "
|
||||||
|
"ALTER TABLE %(table)s DROP CONSTRAINT %(name)s"
|
||||||
|
)
|
||||||
sql_delete_procedure = "DROP FUNCTION %(procedure)s(%(param_types)s)"
|
sql_delete_procedure = "DROP FUNCTION %(procedure)s(%(param_types)s)"
|
||||||
|
|
||||||
def quote_value(self, value):
|
def quote_value(self, value):
|
||||||
|
|
|
@ -209,9 +209,15 @@ def _sqlite_datetime_trunc(lookup_type, dt, tzname, conn_tzname):
|
||||||
elif lookup_type == "hour":
|
elif lookup_type == "hour":
|
||||||
return f"{dt.year:04d}-{dt.month:02d}-{dt.day:02d} {dt.hour:02d}:00:00"
|
return f"{dt.year:04d}-{dt.month:02d}-{dt.day:02d} {dt.hour:02d}:00:00"
|
||||||
elif lookup_type == "minute":
|
elif lookup_type == "minute":
|
||||||
return f"{dt.year:04d}-{dt.month:02d}-{dt.day:02d} {dt.hour:02d}:{dt.minute:02d}:00"
|
return (
|
||||||
|
f"{dt.year:04d}-{dt.month:02d}-{dt.day:02d} "
|
||||||
|
f"{dt.hour:02d}:{dt.minute:02d}:00"
|
||||||
|
)
|
||||||
elif lookup_type == "second":
|
elif lookup_type == "second":
|
||||||
return f"{dt.year:04d}-{dt.month:02d}-{dt.day:02d} {dt.hour:02d}:{dt.minute:02d}:{dt.second:02d}"
|
return (
|
||||||
|
f"{dt.year:04d}-{dt.month:02d}-{dt.day:02d} "
|
||||||
|
f"{dt.hour:02d}:{dt.minute:02d}:{dt.second:02d}"
|
||||||
|
)
|
||||||
raise ValueError(f"Unsupported lookup type: {lookup_type!r}")
|
raise ValueError(f"Unsupported lookup type: {lookup_type!r}")
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -57,26 +57,34 @@ class DatabaseFeatures(BaseDatabaseFeatures):
|
||||||
def django_test_skips(self):
|
def django_test_skips(self):
|
||||||
skips = {
|
skips = {
|
||||||
"SQLite stores values rounded to 15 significant digits.": {
|
"SQLite stores values rounded to 15 significant digits.": {
|
||||||
"model_fields.test_decimalfield.DecimalFieldTests.test_fetch_from_db_without_float_rounding",
|
"model_fields.test_decimalfield.DecimalFieldTests."
|
||||||
|
"test_fetch_from_db_without_float_rounding",
|
||||||
},
|
},
|
||||||
"SQLite naively remakes the table on field alteration.": {
|
"SQLite naively remakes the table on field alteration.": {
|
||||||
"schema.tests.SchemaTests.test_unique_no_unnecessary_fk_drops",
|
"schema.tests.SchemaTests.test_unique_no_unnecessary_fk_drops",
|
||||||
"schema.tests.SchemaTests.test_unique_and_reverse_m2m",
|
"schema.tests.SchemaTests.test_unique_and_reverse_m2m",
|
||||||
"schema.tests.SchemaTests.test_alter_field_default_doesnt_perform_queries",
|
"schema.tests.SchemaTests."
|
||||||
"schema.tests.SchemaTests.test_rename_column_renames_deferred_sql_references",
|
"test_alter_field_default_doesnt_perform_queries",
|
||||||
|
"schema.tests.SchemaTests."
|
||||||
|
"test_rename_column_renames_deferred_sql_references",
|
||||||
},
|
},
|
||||||
"SQLite doesn't support negative precision for ROUND().": {
|
"SQLite doesn't support negative precision for ROUND().": {
|
||||||
"db_functions.math.test_round.RoundTests.test_null_with_negative_precision",
|
"db_functions.math.test_round.RoundTests."
|
||||||
"db_functions.math.test_round.RoundTests.test_decimal_with_negative_precision",
|
"test_null_with_negative_precision",
|
||||||
"db_functions.math.test_round.RoundTests.test_float_with_negative_precision",
|
"db_functions.math.test_round.RoundTests."
|
||||||
"db_functions.math.test_round.RoundTests.test_integer_with_negative_precision",
|
"test_decimal_with_negative_precision",
|
||||||
|
"db_functions.math.test_round.RoundTests."
|
||||||
|
"test_float_with_negative_precision",
|
||||||
|
"db_functions.math.test_round.RoundTests."
|
||||||
|
"test_integer_with_negative_precision",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
if Database.sqlite_version_info < (3, 27):
|
if Database.sqlite_version_info < (3, 27):
|
||||||
skips.update(
|
skips.update(
|
||||||
{
|
{
|
||||||
"Nondeterministic failure on SQLite < 3.27.": {
|
"Nondeterministic failure on SQLite < 3.27.": {
|
||||||
"expressions_window.tests.WindowFunctionTests.test_subquery_row_range_rank",
|
"expressions_window.tests.WindowFunctionTests."
|
||||||
|
"test_subquery_row_range_rank",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -85,8 +93,10 @@ class DatabaseFeatures(BaseDatabaseFeatures):
|
||||||
{
|
{
|
||||||
"the sqlite backend's close() method is a no-op when using an "
|
"the sqlite backend's close() method is a no-op when using an "
|
||||||
"in-memory database": {
|
"in-memory database": {
|
||||||
"servers.test_liveserverthread.LiveServerThreadTest.test_closes_connections",
|
"servers.test_liveserverthread.LiveServerThreadTest."
|
||||||
"servers.tests.LiveServerTestCloseConnectionTest.test_closes_connections",
|
"test_closes_connections",
|
||||||
|
"servers.tests.LiveServerTestCloseConnectionTest."
|
||||||
|
"test_closes_connections",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
@ -146,7 +146,14 @@ class DatabaseIntrospection(BaseDatabaseIntrospection):
|
||||||
)
|
)
|
||||||
return {
|
return {
|
||||||
column_name: (ref_column_name, ref_table_name)
|
column_name: (ref_column_name, ref_table_name)
|
||||||
for _, _, ref_table_name, column_name, ref_column_name, *_ in cursor.fetchall()
|
for (
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
ref_table_name,
|
||||||
|
column_name,
|
||||||
|
ref_column_name,
|
||||||
|
*_,
|
||||||
|
) in cursor.fetchall()
|
||||||
}
|
}
|
||||||
|
|
||||||
def get_primary_key_column(self, cursor, table_name):
|
def get_primary_key_column(self, cursor, table_name):
|
||||||
|
|
|
@ -168,7 +168,9 @@ class DatabaseOperations(BaseDatabaseOperations):
|
||||||
|
|
||||||
def last_executed_query(self, cursor, sql, params):
|
def last_executed_query(self, cursor, sql, params):
|
||||||
# Python substitutes parameters in Modules/_sqlite/cursor.c with:
|
# Python substitutes parameters in Modules/_sqlite/cursor.c with:
|
||||||
# pysqlite_statement_bind_parameters(self->statement, parameters, allow_8bit_chars);
|
# pysqlite_statement_bind_parameters(
|
||||||
|
# self->statement, parameters, allow_8bit_chars
|
||||||
|
# );
|
||||||
# Unfortunately there is no way to reach self->statement from Python,
|
# Unfortunately there is no way to reach self->statement from Python,
|
||||||
# so we quote and substitute parameters manually.
|
# so we quote and substitute parameters manually.
|
||||||
if params:
|
if params:
|
||||||
|
@ -271,7 +273,8 @@ class DatabaseOperations(BaseDatabaseOperations):
|
||||||
value = timezone.make_naive(value, self.connection.timezone)
|
value = timezone.make_naive(value, self.connection.timezone)
|
||||||
else:
|
else:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
"SQLite backend does not support timezone-aware datetimes when USE_TZ is False."
|
"SQLite backend does not support timezone-aware datetimes when "
|
||||||
|
"USE_TZ is False."
|
||||||
)
|
)
|
||||||
|
|
||||||
return str(value)
|
return str(value)
|
||||||
|
|
|
@ -468,12 +468,15 @@ class DatabaseSchemaEditor(BaseDatabaseSchemaEditor):
|
||||||
old_field.remote_field.through._meta.db_table
|
old_field.remote_field.through._meta.db_table
|
||||||
== new_field.remote_field.through._meta.db_table
|
== new_field.remote_field.through._meta.db_table
|
||||||
):
|
):
|
||||||
# The field name didn't change, but some options did; we have to propagate this altering.
|
# The field name didn't change, but some options did, so we have to
|
||||||
|
# propagate this altering.
|
||||||
self._remake_table(
|
self._remake_table(
|
||||||
old_field.remote_field.through,
|
old_field.remote_field.through,
|
||||||
alter_field=(
|
alter_field=(
|
||||||
# We need the field that points to the target model, so we can tell alter_field to change it -
|
# The field that points to the target model is needed, so
|
||||||
# this is m2m_reverse_field_name() (as opposed to m2m_field_name, which points to our model)
|
# we can tell alter_field to change it - this is
|
||||||
|
# m2m_reverse_field_name() (as opposed to m2m_field_name(),
|
||||||
|
# which points to our model).
|
||||||
old_field.remote_field.through._meta.get_field(
|
old_field.remote_field.through._meta.get_field(
|
||||||
old_field.m2m_reverse_field_name()
|
old_field.m2m_reverse_field_name()
|
||||||
),
|
),
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue