Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/main'
Browse files Browse the repository at this point in the history
  • Loading branch information
dan-mm committed Nov 2, 2023
2 parents a6e7078 + 797957f commit a1f33ad
Show file tree
Hide file tree
Showing 15 changed files with 123 additions and 25 deletions.
1 change: 1 addition & 0 deletions AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ answer newbie questions, and generally made Django that much better:
ant9000@netwise.it
Anthony Briggs <anthony.briggs@gmail.com>
Anthony Wright <ryow.college@gmail.com>
Antoine Chéneau <antoine.cheneau@outlook.com>
Anton Samarchyan <desecho@gmail.com>
Antoni Aloy
Antonio Cavedoni <http://cavedoni.com/>
Expand Down
1 change: 1 addition & 0 deletions django/db/backends/base/features.py
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,7 @@ class BaseDatabaseFeatures:
"cs": None, # Case-sensitive.
"non_default": None, # Non-default.
"swedish_ci": None, # Swedish case-insensitive.
"virtual": None, # A collation that can be used for virtual columns.
}
# SQL template override for tests.aggregation.tests.NowUTC
test_now_utc_template = None
Expand Down
1 change: 1 addition & 0 deletions django/db/backends/mysql/features.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ def test_collations(self):
"ci": f"{charset}_general_ci",
"non_default": f"{charset}_esperanto_ci",
"swedish_ci": f"{charset}_swedish_ci",
"virtual": f"{charset}_esperanto_ci",
}

test_now_utc_template = "UTC_TIMESTAMP(6)"
Expand Down
20 changes: 14 additions & 6 deletions django/db/backends/oracle/features.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,12 +80,6 @@ class DatabaseFeatures(BaseDatabaseFeatures):
supports_comparing_boolean_expr = False
supports_json_field_contains = False
supports_collation_on_textfield = False
test_collations = {
"ci": "BINARY_CI",
"cs": "BINARY",
"non_default": "SWEDISH_CI",
"swedish_ci": "SWEDISH_CI",
}
test_now_utc_template = "CURRENT_TIMESTAMP AT TIME ZONE 'UTC'"

django_test_skips = {
Expand Down Expand Up @@ -125,6 +119,10 @@ class DatabaseFeatures(BaseDatabaseFeatures):
"Oracle doesn't support comparing NCLOB to NUMBER.": {
"generic_relations_regress.tests.GenericRelationTests.test_textlink_filter",
},
"DecimalField.db_default doesn't return decimal.Decimal instances on Oracle "
"(#34941).": {
"field_defaults.tests.DefaultTests.test_field_db_defaults_returning",
},
}
django_test_expected_failures = {
# A bug in Django/oracledb with respect to string handling (#23843).
Expand All @@ -148,6 +146,16 @@ def introspected_field_types(self):
"TimeField": "DateTimeField",
}

@cached_property
def test_collations(self):
return {
"ci": "BINARY_CI",
"cs": "BINARY",
"non_default": "SWEDISH_CI",
"swedish_ci": "SWEDISH_CI",
"virtual": "SWEDISH_CI" if self.supports_collation_on_charfield else None,
}

@cached_property
def supports_collation_on_charfield(self):
with self.connection.cursor() as cursor:
Expand Down
1 change: 1 addition & 0 deletions django/db/backends/postgresql/features.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ class DatabaseFeatures(BaseDatabaseFeatures):
"deterministic": "C",
"non_default": "sv-x-icu",
"swedish_ci": "sv-x-icu",
"virtual": "sv-x-icu",
}
test_now_utc_template = "STATEMENT_TIMESTAMP() AT TIME ZONE 'UTC'"
insert_test_table_with_defaults = "INSERT INTO {} DEFAULT VALUES"
Expand Down
1 change: 1 addition & 0 deletions django/db/backends/sqlite3/features.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ class DatabaseFeatures(BaseDatabaseFeatures):
"ci": "nocase",
"cs": "binary",
"non_default": "nocase",
"virtual": "nocase",
}
django_test_expected_failures = {
# The django_format_dtdelta() function doesn't properly handle mixed
Expand Down
2 changes: 1 addition & 1 deletion django/db/models/expressions.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ def as_sqlite(self, compiler, connection, **extra_context):
sql, params = self.as_sql(compiler, connection, **extra_context)
try:
if self.output_field.get_internal_type() == "DecimalField":
sql = "CAST(%s AS NUMERIC)" % sql
sql = "(CAST(%s AS NUMERIC))" % sql
except FieldError:
pass
return sql, params
Expand Down
2 changes: 2 additions & 0 deletions django/forms/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -1211,6 +1211,7 @@ def _get_foreign_key(parent_model, model, fk_name=None, can_fail=False):
if len(fks_to_parent) == 1:
fk = fks_to_parent[0]
parent_list = parent_model._meta.get_parent_list()
parent_list.append(parent_model)
if (
not isinstance(fk, ForeignKey)
or (
Expand All @@ -1236,6 +1237,7 @@ def _get_foreign_key(parent_model, model, fk_name=None, can_fail=False):
else:
# Try to discover what the ForeignKey from model to parent_model is
parent_list = parent_model._meta.get_parent_list()
parent_list.append(parent_model)
fks_to_parent = [
f
for f in opts.fields
Expand Down
10 changes: 10 additions & 0 deletions docs/ref/contrib/staticfiles.txt
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,16 @@ For example, the ``'css/styles.css'`` file with this content:

@import url("../admin/css/base.27e20196a850.css");

.. admonition:: Usage of the ``integrity`` HTML attribute with local files

When using the optional ``integrity`` attribute within tags like
``<script>`` or ``<link>``, its value should be calculated based on the
files as they are served, not as stored in the filesystem. This is
particularly important because depending on how static files are collected,
their checksum may have changed (for example when using
:djadmin:`collectstatic`). At the moment, there is no out-of-the-box
tooling available for this.

You can change the location of the manifest file by using a custom
``ManifestStaticFilesStorage`` subclass that sets the ``manifest_storage``
argument. For example::
Expand Down
4 changes: 4 additions & 0 deletions tests/field_defaults/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"""

from datetime import datetime
from decimal import Decimal

from django.db import models
from django.db.models.functions import Coalesce, ExtractYear, Now, Pi
Expand All @@ -33,6 +34,9 @@ class DBArticle(models.Model):

headline = models.CharField(max_length=100, db_default="Default headline")
pub_date = models.DateTimeField(db_default=Now())
cost = models.DecimalField(
max_digits=3, decimal_places=2, db_default=Decimal("3.33")
)

class Meta:
required_db_features = {"supports_expression_defaults"}
Expand Down
9 changes: 6 additions & 3 deletions tests/field_defaults/tests.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from datetime import datetime
from decimal import Decimal
from math import pi

from django.db import connection
Expand Down Expand Up @@ -44,6 +45,7 @@ def test_field_db_defaults_returning(self):
self.assertIsInstance(a.id, int)
self.assertEqual(a.headline, "Default headline")
self.assertIsInstance(a.pub_date, datetime)
self.assertEqual(a.cost, Decimal("3.33"))

@skipIfDBFeature("can_return_columns_from_insert")
@skipUnlessDBFeature("supports_expression_defaults")
Expand All @@ -54,6 +56,7 @@ def test_field_db_defaults_refresh(self):
self.assertIsInstance(a.id, int)
self.assertEqual(a.headline, "Default headline")
self.assertIsInstance(a.pub_date, datetime)
self.assertEqual(a.cost, Decimal("3.33"))

def test_null_db_default(self):
obj1 = DBDefaults.objects.create()
Expand Down Expand Up @@ -141,12 +144,12 @@ def test_bulk_create_all_db_defaults_one_field(self):
articles = [DBArticle(pub_date=pub_date), DBArticle(pub_date=pub_date)]
DBArticle.objects.bulk_create(articles)

headlines = DBArticle.objects.values_list("headline", "pub_date")
headlines = DBArticle.objects.values_list("headline", "pub_date", "cost")
self.assertSequenceEqual(
headlines,
[
("Default headline", pub_date),
("Default headline", pub_date),
("Default headline", pub_date, Decimal("3.33")),
("Default headline", pub_date, Decimal("3.33")),
],
)

Expand Down
38 changes: 38 additions & 0 deletions tests/migrations/test_operations.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import math
from decimal import Decimal

from django.core.exceptions import FieldDoesNotExist
from django.db import IntegrityError, connection, migrations, models, transaction
Expand Down Expand Up @@ -2210,6 +2211,43 @@ def test_alter_field_change_nullable_to_database_default_not_null(self):
pony = project_state.apps.get_model(app_label, "pony").objects.create(weight=1)
self.assertIsNone(pony.green)

def test_alter_field_change_nullable_to_decimal_database_default_not_null(self):
app_label = "test_alflcntdddn"
project_state = self.set_up_test_model(app_label)
operation_1 = migrations.AddField(
"Pony",
"height",
models.DecimalField(null=True, max_digits=5, decimal_places=2),
)
operation_2 = migrations.AlterField(
"Pony",
"height",
models.DecimalField(
max_digits=5, decimal_places=2, db_default=Decimal("12.22")
),
)
table_name = f"{app_label}_pony"
self.assertColumnNotExists(table_name, "height")
# Add field.
new_state = project_state.clone()
operation_1.state_forwards(app_label, new_state)
with connection.schema_editor() as editor:
operation_1.database_forwards(app_label, editor, project_state, new_state)
self.assertColumnExists(table_name, "height")
old_pony = new_state.apps.get_model(app_label, "pony").objects.create(weight=1)
self.assertIsNone(old_pony.height)
# Alter field.
project_state, new_state = new_state, new_state.clone()
operation_2.state_forwards(app_label, new_state)
with connection.schema_editor() as editor:
operation_2.database_forwards(app_label, editor, project_state, new_state)
old_pony.refresh_from_db()
self.assertEqual(old_pony.height, Decimal("12.22"))
pony = new_state.apps.get_model(app_label, "pony").objects.create(weight=2)
if not connection.features.can_return_columns_from_insert:
pony.refresh_from_db()
self.assertEqual(pony.height, Decimal("12.22"))

@skipIfDBFeature("interprets_empty_strings_as_nulls")
def test_alter_field_change_blank_nullable_database_default_to_not_null(self):
app_label = "test_alflcbnddnn"
Expand Down
12 changes: 3 additions & 9 deletions tests/model_fields/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@


test_collation = SimpleLazyObject(
lambda: connection.features.test_collations.get("non_default")
lambda: connection.features.test_collations["virtual"]
)


Expand Down Expand Up @@ -529,10 +529,7 @@ class GeneratedModelOutputField(models.Model):
)

class Meta:
required_db_features = {
"supports_stored_generated_columns",
"supports_collation_on_charfield",
}
required_db_features = {"supports_stored_generated_columns"}


class GeneratedModelOutputFieldVirtual(models.Model):
Expand All @@ -544,10 +541,7 @@ class GeneratedModelOutputFieldVirtual(models.Model):
)

class Meta:
required_db_features = {
"supports_virtual_generated_columns",
"supports_collation_on_charfield",
}
required_db_features = {"supports_virtual_generated_columns"}


class GeneratedModelNull(models.Model):
Expand Down
7 changes: 1 addition & 6 deletions tests/model_fields/test_generatedfield.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,12 +165,8 @@ def test_output_field_lookups(self):
with self.assertNumQueries(0), self.assertRaises(does_not_exist):
self.base_model.objects.get(field__gte=overflow_value)

@skipUnlessDBFeature("supports_collation_on_charfield")
def test_output_field(self):
collation = connection.features.test_collations.get("non_default")
if not collation:
self.skipTest("Language collations are not supported.")

collation = connection.features.test_collations["virtual"]
m = self.output_field_model.objects.create(name="NAME")
field = m._meta.get_field("lower_name")
db_parameters = field.db_parameters(connection)
Expand All @@ -181,7 +177,6 @@ def test_output_field(self):
field._resolved_expression.output_field.db_type(connection),
)

@skipUnlessDBFeature("supports_collation_on_charfield")
def test_db_type_parameters(self):
db_type_parameters = self.output_field_model._meta.get_field(
"lower_name"
Expand Down
39 changes: 39 additions & 0 deletions tests/modeladmin/test_checks.py
Original file line number Diff line number Diff line change
Expand Up @@ -1268,6 +1268,45 @@ class TestModelAdmin(ModelAdmin):

self.assertIsValid(TestModelAdmin, ValidationTestModel)

def test_proxy_model(self):
class Reporter(Model):
pass

class ProxyJournalist(Reporter):
class Meta:
proxy = True

class Article(Model):
reporter = ForeignKey(ProxyJournalist, on_delete=CASCADE)

class ArticleInline(admin.TabularInline):
model = Article

class ReporterAdmin(admin.ModelAdmin):
inlines = [ArticleInline]

self.assertIsValid(ReporterAdmin, Reporter)

def test_proxy_model_fk_name(self):
class ReporterFkName(Model):
pass

class ProxyJournalistFkName(ReporterFkName):
class Meta:
proxy = True

class ArticleFkName(Model):
reporter = ForeignKey(ProxyJournalistFkName, on_delete=CASCADE)

class ArticleInline(admin.TabularInline):
model = ArticleFkName
fk_name = "reporter"

class ReporterAdmin(admin.ModelAdmin):
inlines = [ArticleInline]

self.assertIsValid(ReporterAdmin, ReporterFkName)

def test_proxy_model_parent(self):
class Parent(Model):
pass
Expand Down

0 comments on commit a1f33ad

Please sign in to comment.