From 00152276e9a26fb06ccf44d8d56525a892c27125 Mon Sep 17 00:00:00 2001 From: Mariusz Felisiak Date: Wed, 3 May 2023 13:51:05 +0200 Subject: [PATCH 01/47] [4.2.x] Post-release version bump. --- django/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/django/__init__.py b/django/__init__.py index e5fc759960bf..addd783d90f7 100644 --- a/django/__init__.py +++ b/django/__init__.py @@ -1,6 +1,6 @@ from django.utils.version import get_version -VERSION = (4, 2, 1, "final", 0) +VERSION = (4, 2, 2, "alpha", 0) __version__ = get_version(VERSION) From 110919987b9a19644f5b650d4de345fea76d4a9b Mon Sep 17 00:00:00 2001 From: Mariusz Felisiak Date: Wed, 3 May 2023 15:13:07 +0200 Subject: [PATCH 02/47] [4.2.x] Added stub release notes for 4.2.2. Backport of b0d3a5de95c9966075c38f10e790dced70c81ebf from main --- docs/releases/4.2.2.txt | 12 ++++++++++++ docs/releases/index.txt | 1 + 2 files changed, 13 insertions(+) create mode 100644 docs/releases/4.2.2.txt diff --git a/docs/releases/4.2.2.txt b/docs/releases/4.2.2.txt new file mode 100644 index 000000000000..31f854b00411 --- /dev/null +++ b/docs/releases/4.2.2.txt @@ -0,0 +1,12 @@ +========================== +Django 4.2.2 release notes +========================== + +*Expected June 5, 2023* + +Django 4.2.2 fixes several bugs in 4.2.1. + +Bugfixes +======== + +* ... diff --git a/docs/releases/index.txt b/docs/releases/index.txt index 03f88db8f609..8c186a582001 100644 --- a/docs/releases/index.txt +++ b/docs/releases/index.txt @@ -26,6 +26,7 @@ versions of the documentation contain the release notes for any later releases. .. toctree:: :maxdepth: 1 + 4.2.2 4.2.1 4.2 From 2756c6960163f0263a15633fd3cfd93281f47496 Mon Sep 17 00:00:00 2001 From: Mariusz Felisiak Date: Wed, 3 May 2023 15:20:31 +0200 Subject: [PATCH 03/47] [4.2.x] Added CVE-2023-31047 to security archive. Backport of 49830025c992fbc8d8f213e7c16dba1391c6adf2 from main --- docs/releases/security.txt | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/docs/releases/security.txt b/docs/releases/security.txt index 0a8273870943..c90d7323978b 100644 --- a/docs/releases/security.txt +++ b/docs/releases/security.txt @@ -36,6 +36,17 @@ Issues under Django's security process All security issues have been handled under versions of Django's security process. These are listed below. +May 3, 2023 - :cve:`2023-31047` +------------------------------- + +Potential bypass of validation when uploading multiple files using one form +field. `Full description +`__ + +* Django 4.2 :commit:`(patch) <21b1b1fc03e5f9e9f8c977ee6e35618dd3b353dd>` +* Django 4.1 :commit:`(patch) ` +* Django 3.2 :commit:`(patch) ` + February 14, 2023 - :cve:`2023-24580` ------------------------------------- From 9ec1ff7879563942bb43cfb33ac40a94cdca3b40 Mon Sep 17 00:00:00 2001 From: Mariusz Felisiak Date: Thu, 4 May 2023 08:09:02 +0200 Subject: [PATCH 04/47] [4.2.x] Fixed MultipleFileFieldTest.test_file_multiple_validation() test if Pillow isn't installed. Follow up to fb4c55d9ec4bb812a7fb91fa20510d91645e411b. Backport of fcfbf08abe3e6dc54894df6988024f055abc6c40 from main --- tests/forms_tests/field_tests/test_filefield.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/forms_tests/field_tests/test_filefield.py b/tests/forms_tests/field_tests/test_filefield.py index 00c74a7c1aa2..11388bdc09df 100644 --- a/tests/forms_tests/field_tests/test_filefield.py +++ b/tests/forms_tests/field_tests/test_filefield.py @@ -1,4 +1,5 @@ import pickle +import unittest from django.core.exceptions import ValidationError from django.core.files.uploadedfile import SimpleUploadedFile @@ -6,6 +7,13 @@ from django.forms import FileField, FileInput from django.test import SimpleTestCase +try: + from PIL import Image # NOQA +except ImportError: + HAS_PILLOW = False +else: + HAS_PILLOW = True + class FileFieldTest(SimpleTestCase): def test_filefield_1(self): @@ -151,6 +159,7 @@ def test_file_multiple_empty(self): with self.assertRaisesMessage(ValidationError, msg): f.clean(files[::-1]) + @unittest.skipUnless(HAS_PILLOW, "Pillow not installed") def test_file_multiple_validation(self): f = MultipleFileField(validators=[validate_image_file_extension]) From 4eaed191b6514dc577fdba31b31c0a7571b176e5 Mon Sep 17 00:00:00 2001 From: Jannis Vajen Date: Thu, 4 May 2023 13:56:36 +0200 Subject: [PATCH 05/47] [4.2.x] Corrected code-block directives in docs. Backport of 024954aad4c422a091b7afab42fff1a9d7478fce from main --- docs/ref/files/file.txt | 2 +- docs/ref/templates/builtins.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/ref/files/file.txt b/docs/ref/files/file.txt index f5c1b10917be..650bbb70795d 100644 --- a/docs/ref/files/file.txt +++ b/docs/ref/files/file.txt @@ -135,7 +135,7 @@ below) will also have a couple of extra methods: Saves a new file with the file name and contents provided. This will not replace the existing file, but will create a new file and update the object to point to it. If ``save`` is ``True``, the model's ``save()`` method will - be called once the file is saved. That is, these two lines:: + be called once the file is saved. That is, these two lines: .. code-block:: pycon diff --git a/docs/ref/templates/builtins.txt b/docs/ref/templates/builtins.txt index c7a849896105..8a0457791941 100644 --- a/docs/ref/templates/builtins.txt +++ b/docs/ref/templates/builtins.txt @@ -1116,7 +1116,7 @@ Example usage: {% resetcycle %} {% endfor %} -This example would return this HTML:: +This example would return this HTML: .. code-block:: html From bcf66f135595c4a305f45bcfeafcd86af72b5290 Mon Sep 17 00:00:00 2001 From: Pan Dango <76955186+hoopandango@users.noreply.github.com> Date: Sun, 7 May 2023 18:21:27 +0530 Subject: [PATCH 06/47] [4.2.x] Corrected code-block directive in docs/ref/templates/builtins.txt. Backport of 12ec80726f33e8dbd80de3cecf48d76ac4c0aa89 from main --- docs/ref/templates/builtins.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ref/templates/builtins.txt b/docs/ref/templates/builtins.txt index 8a0457791941..853a62e71962 100644 --- a/docs/ref/templates/builtins.txt +++ b/docs/ref/templates/builtins.txt @@ -1264,7 +1264,7 @@ such as this: path("clients/", include("project_name.app_name.urls")) -...then, in a template, you can create a link to this view like this:: +...then, in a template, you can create a link to this view like this: .. code-block:: html+django From dc3b8190ed2b01e450c81df28023f0b6352b4a27 Mon Sep 17 00:00:00 2001 From: Akash Kumar Sen <71623442+Akash-Kumar-Sen@users.noreply.github.com> Date: Mon, 8 May 2023 12:04:23 +0530 Subject: [PATCH 07/47] [4.2.x] Fixed #34545 -- Corrected the number of months in installation FAQ. Backport of aaf8c76c567e8311f4a85cf74c82fc3d70cc6f12 from main --- docs/faq/install.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/faq/install.txt b/docs/faq/install.txt index a0731fc71736..fc19dda0ab07 100644 --- a/docs/faq/install.txt +++ b/docs/faq/install.txt @@ -82,7 +82,7 @@ Should I use the stable version or development version? Generally, if you're using code in production, you should be using a stable release. The Django project publishes a full stable release -every nine months or so, with bugfix updates in between. These stable +every eight months or so, with bugfix updates in between. These stable releases contain the API that is covered by our backwards compatibility guarantees; if you write code against stable releases, you shouldn't have any problems upgrading when the next official From e0d8981139cd329962e509efb575fdfb2dad4073 Mon Sep 17 00:00:00 2001 From: Mariusz Felisiak Date: Mon, 8 May 2023 19:34:30 +0200 Subject: [PATCH 08/47] [4.2.x] Fixed #34544 -- Avoided DBMS_LOB.SUBSTR() wrapping with IS NULL condition on Oracle. Regression in 09ffc5c1212d4ced58b708cbbf3dfbfb77b782ca. Thanks Michael Smith for the report. This also reverts commit 1e4da439556cdd69eb9f91e07f99cf77997e70d2. Backport of 1586a09b7949bbb7b0d84cb74ce1cadc25cbb355 from main --- django/db/backends/oracle/operations.py | 10 +++------- django/db/backends/postgresql/features.py | 3 +++ docs/releases/4.2.2.txt | 4 +++- tests/lookup/models.py | 12 +----------- tests/lookup/tests.py | 9 ++++++++- 5 files changed, 18 insertions(+), 20 deletions(-) diff --git a/django/db/backends/oracle/operations.py b/django/db/backends/oracle/operations.py index d34ca23bae3a..64b1f82071e6 100644 --- a/django/db/backends/oracle/operations.py +++ b/django/db/backends/oracle/operations.py @@ -296,12 +296,6 @@ def fetch_returned_insert_columns(self, cursor, returning_params): columns.append(value[0]) return tuple(columns) - def field_cast_sql(self, db_type, internal_type): - if db_type and db_type.endswith("LOB") and internal_type != "JSONField": - return "DBMS_LOB.SUBSTR(%s)" - else: - return "%s" - def no_limit_value(self): return None @@ -344,7 +338,9 @@ def last_insert_id(self, cursor, table_name, pk_name): def lookup_cast(self, lookup_type, internal_type=None): if lookup_type in ("iexact", "icontains", "istartswith", "iendswith"): return "UPPER(%s)" - if internal_type == "JSONField" and lookup_type == "exact": + if ( + lookup_type != "isnull" and internal_type in ("BinaryField", "TextField") + ) or (lookup_type == "exact" and internal_type == "JSONField"): return "DBMS_LOB.SUBSTR(%s)" return "%s" diff --git a/django/db/backends/postgresql/features.py b/django/db/backends/postgresql/features.py index aa68465df900..732b30b0a45f 100644 --- a/django/db/backends/postgresql/features.py +++ b/django/db/backends/postgresql/features.py @@ -82,6 +82,9 @@ class DatabaseFeatures(BaseDatabaseFeatures): "indexes.tests.SchemaIndexesNotPostgreSQLTests." "test_create_index_ignores_opclasses", }, + "PostgreSQL requires casting to text.": { + "lookup.tests.LookupTests.test_textfield_exact_null", + }, } @cached_property diff --git a/docs/releases/4.2.2.txt b/docs/releases/4.2.2.txt index 31f854b00411..9d16e7ef6f77 100644 --- a/docs/releases/4.2.2.txt +++ b/docs/releases/4.2.2.txt @@ -9,4 +9,6 @@ Django 4.2.2 fixes several bugs in 4.2.1. Bugfixes ======== -* ... +* Fixed a regression in Django 4.2 that caused an unnecessary + ``DBMS_LOB.SUBSTR()`` wrapping in the ``__isnull`` and ``__exact=None`` + lookups for ``TextField()``/``BinaryField()`` on Oracle (:ticket:`34544`). diff --git a/tests/lookup/models.py b/tests/lookup/models.py index 9bb3412c33eb..75f3e3b6ba4a 100644 --- a/tests/lookup/models.py +++ b/tests/lookup/models.py @@ -19,6 +19,7 @@ def __str__(self): class Author(models.Model): name = models.CharField(max_length=100) alias = models.CharField(max_length=50, null=True, blank=True) + bio = models.TextField(null=True) class Meta: ordering = ("name",) @@ -50,22 +51,11 @@ def get_prep_value(self, value): return None if value == "" else value -class NullField(models.Field): - pass - - -NullField.register_lookup(IsNull) - - @NulledTextField.register_lookup class NulledTransform(models.Transform): lookup_name = "nulled" template = "NULL" - @property - def output_field(self): - return NullField() - @NulledTextField.register_lookup class IsNullWithNoneAsRHS(IsNull): diff --git a/tests/lookup/tests.py b/tests/lookup/tests.py index 503bae18fc09..ab3d968aaceb 100644 --- a/tests/lookup/tests.py +++ b/tests/lookup/tests.py @@ -49,7 +49,7 @@ class LookupTests(TestCase): @classmethod def setUpTestData(cls): # Create a few Authors. - cls.au1 = Author.objects.create(name="Author 1", alias="a1") + cls.au1 = Author.objects.create(name="Author 1", alias="a1", bio="x" * 4001) cls.au2 = Author.objects.create(name="Author 2", alias="a2") # Create a few Articles. cls.a1 = Article.objects.create( @@ -1000,6 +1000,13 @@ def test_regex_null(self): Season.objects.create(year=2012, gt=None) self.assertQuerySetEqual(Season.objects.filter(gt__regex=r"^$"), []) + def test_textfield_exact_null(self): + with self.assertNumQueries(1) as ctx: + self.assertSequenceEqual(Author.objects.filter(bio=None), [self.au2]) + # Columns with IS NULL condition are not wrapped (except PostgreSQL). + bio_column = connection.ops.quote_name(Author._meta.get_field("bio").column) + self.assertIn(f"{bio_column} IS NULL", ctx.captured_queries[0]["sql"]) + def test_regex_non_string(self): """ A regex lookup does not fail on non-string fields From e50fe33e13f15ddeafd6354817b9d96002559751 Mon Sep 17 00:00:00 2001 From: nessita <124304+nessita@users.noreply.github.com> Date: Thu, 11 May 2023 07:55:45 -0300 Subject: [PATCH 09/47] [4.2.x] Made explicit the location of locally-built HTML docs. Backport of 2b11740e1d9d23ef53d94a1c45896fb7b91df908 from main --- docs/internals/contributing/writing-documentation.txt | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/internals/contributing/writing-documentation.txt b/docs/internals/contributing/writing-documentation.txt index 73147c82bf27..fa3cd749f9a5 100644 --- a/docs/internals/contributing/writing-documentation.txt +++ b/docs/internals/contributing/writing-documentation.txt @@ -60,10 +60,11 @@ Then from the ``docs`` directory, build the HTML: To get started contributing, you'll want to read the :ref:`reStructuredText reference `. -Your locally-built documentation will be themed differently than the -documentation at `docs.djangoproject.com `_. -This is OK! If your changes look good on your local machine, they'll look good -on the website. +Your locally-built documentation will be accessible at +``docs/_build/html/index.html`` and it can be viewed in any web browser, though +it will be themed differently than the documentation at +`docs.djangoproject.com `_. This is OK! If +your changes look good on your local machine, they'll look good on the website. How the documentation is organized ================================== From dbe263751cf80732c2cd47d409f5f0a9701ec327 Mon Sep 17 00:00:00 2001 From: Alberto Sottile Date: Fri, 12 May 2023 13:09:38 +0200 Subject: [PATCH 10/47] [4.2.x] Clarified database connections lifetime outside HTTP requests. Backport of e901407e2369ddb16a5c866e1f2fbf8ea8acf549 from main --- docs/ref/databases.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/ref/databases.txt b/docs/ref/databases.txt index 3334619f9191..5a26520501ae 100644 --- a/docs/ref/databases.txt +++ b/docs/ref/databases.txt @@ -31,7 +31,7 @@ Persistent connections ---------------------- Persistent connections avoid the overhead of reestablishing a connection to -the database in each request. They're controlled by the +the database in each HTTP request. They're controlled by the :setting:`CONN_MAX_AGE` parameter which defines the maximum lifetime of a connection. It can be set independently for each database. @@ -101,6 +101,10 @@ either restore Django's defaults at the end of each request, force an appropriate value at the beginning of each request, or disable persistent connections. +If a connection is created in a long-running process, outside of Django’s +request-response cycle, the connection will remain open until explicitly +closed, or timeout occurs. + Encoding -------- From ddccecee91601ce790c82b0aa03b2fa751580361 Mon Sep 17 00:00:00 2001 From: Alexerson Date: Fri, 12 May 2023 06:34:47 -0700 Subject: [PATCH 11/47] [4.2.x] Fixed #34556 -- Doc'd that StreamingHttpResponse accepts memoryviews and strings iterators. Backport of 599f3e2cda50ab084915ffd08edb5ad6cad61415 from main --- docs/ref/request-response.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/ref/request-response.txt b/docs/ref/request-response.txt index 2c195b6f9001..c8e55ea37036 100644 --- a/docs/ref/request-response.txt +++ b/docs/ref/request-response.txt @@ -1204,9 +1204,9 @@ The :class:`StreamingHttpResponse` is not a subclass of :class:`HttpResponse`, because it features a slightly different API. However, it is almost identical, with the following notable differences: -* It should be given an iterator that yields bytestrings as content. When - serving under WSGI, this should be a sync iterator. When serving under ASGI, - this is should an async iterator. +* It should be given an iterator that yields bytestrings, :class:`memoryview`, + or strings as content. When serving under WSGI, this should be a sync + iterator. When serving under ASGI, then it should be an async iterator. * You cannot access its content, except by iterating the response object itself. This should only occur when the response is returned to the client: From 9c301814b0d342bfc5f10c1513594ce5fbb6c6a9 Mon Sep 17 00:00:00 2001 From: Julie Rymer Date: Mon, 15 May 2023 15:19:38 +0200 Subject: [PATCH 12/47] [4.2.x] Fixed #34539 -- Restored get_prep_value() call when adapting JSONFields. Regression in 5c23d9f0c32f166c81ecb6f3f01d5077a6084318. Backport of 0ec60661e61b153e6bcec64649b1b7f524eb3e18 from main --- AUTHORS | 1 + django/db/models/fields/json.py | 2 ++ docs/releases/4.2.2.txt | 3 +++ tests/model_fields/test_jsonfield.py | 23 +++++++++++++++++++++++ 4 files changed, 29 insertions(+) diff --git a/AUTHORS b/AUTHORS index 2cddbf9280b2..af30e8d78efc 100644 --- a/AUTHORS +++ b/AUTHORS @@ -530,6 +530,7 @@ answer newbie questions, and generally made Django that much better: Julia Elman Julia Matsieva Julian Bez + Julie Rymer Julien Phalip Junyoung Choi junzhang.jn@gmail.com diff --git a/django/db/models/fields/json.py b/django/db/models/fields/json.py index eb2d35f10058..b7cde157c4fa 100644 --- a/django/db/models/fields/json.py +++ b/django/db/models/fields/json.py @@ -99,6 +99,8 @@ def get_internal_type(self): return "JSONField" def get_db_prep_value(self, value, connection, prepared=False): + if not prepared: + value = self.get_prep_value(value) # RemovedInDjango51Warning: When the deprecation ends, replace with: # if ( # isinstance(value, expressions.Value) diff --git a/docs/releases/4.2.2.txt b/docs/releases/4.2.2.txt index 9d16e7ef6f77..a92582b7a03e 100644 --- a/docs/releases/4.2.2.txt +++ b/docs/releases/4.2.2.txt @@ -12,3 +12,6 @@ Bugfixes * Fixed a regression in Django 4.2 that caused an unnecessary ``DBMS_LOB.SUBSTR()`` wrapping in the ``__isnull`` and ``__exact=None`` lookups for ``TextField()``/``BinaryField()`` on Oracle (:ticket:`34544`). + +* Restored, following a regression in Django 4.2, ``get_prep_value()`` call in + ``JSONField`` subclasses (:ticket:`34539`). diff --git a/tests/model_fields/test_jsonfield.py b/tests/model_fields/test_jsonfield.py index 60357d87b2db..4a1cc075b4c4 100644 --- a/tests/model_fields/test_jsonfield.py +++ b/tests/model_fields/test_jsonfield.py @@ -103,6 +103,29 @@ def test_key_transform_text_lookup_mixin_non_key_transform(self): with self.assertRaisesMessage(TypeError, msg): KeyTransformTextLookupMixin(transform) + def test_get_prep_value(self): + class JSONFieldGetPrepValue(models.JSONField): + def get_prep_value(self, value): + if value is True: + return {"value": True} + return value + + def noop_adapt_json_value(value, encoder): + return value + + field = JSONFieldGetPrepValue() + with mock.patch.object( + connection.ops, "adapt_json_value", noop_adapt_json_value + ): + self.assertEqual( + field.get_db_prep_value(True, connection, prepared=False), + {"value": True}, + ) + self.assertIs( + field.get_db_prep_value(True, connection, prepared=True), True + ) + self.assertEqual(field.get_db_prep_value(1, connection, prepared=False), 1) + class TestValidation(SimpleTestCase): def test_invalid_encoder(self): From 201d29b3719ef15637648be7bd947ef90a66ab55 Mon Sep 17 00:00:00 2001 From: Simon Charette Date: Tue, 16 May 2023 15:11:19 -0400 Subject: [PATCH 13/47] [4.2.x] Fixed #34570 -- Silenced noop deferral of many-to-many and GFK. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While deferring many-to-many and GFK has no effect, the previous implementation of QuerySet.defer() ignore them instead of crashing. Regression in b3db6c8dcb5145f7d45eff517bcd96460475c879. Thanks Paco Martínez for the report. Backport of 99e5dff737cd20b12d060e4794e097063b61ec40 from main --- django/db/models/sql/query.py | 10 +++++++++- docs/releases/4.2.2.txt | 4 ++++ tests/defer_regress/tests.py | 6 ++++++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/django/db/models/sql/query.py b/django/db/models/sql/query.py index b347c6bf3f10..b615d06f28fb 100644 --- a/django/db/models/sql/query.py +++ b/django/db/models/sql/query.py @@ -725,7 +725,15 @@ def _get_defer_select_mask(self, opts, mask, select_mask=None): field_select_mask = select_mask.setdefault((field_name, relation), {}) field = relation.field else: - field = opts.get_field(field_name).field + reverse_rel = opts.get_field(field_name) + # While virtual fields such as many-to-many and generic foreign + # keys cannot be effectively deferred we've historically + # allowed them to be passed to QuerySet.defer(). Ignore such + # field references until a layer of validation at mask + # alteration time will be implemented eventually. + if not hasattr(reverse_rel, "field"): + continue + field = reverse_rel.field field_select_mask = select_mask.setdefault(field, {}) related_model = field.model._meta.concrete_model self._get_defer_select_mask( diff --git a/docs/releases/4.2.2.txt b/docs/releases/4.2.2.txt index a92582b7a03e..ca21e5f1ec94 100644 --- a/docs/releases/4.2.2.txt +++ b/docs/releases/4.2.2.txt @@ -15,3 +15,7 @@ Bugfixes * Restored, following a regression in Django 4.2, ``get_prep_value()`` call in ``JSONField`` subclasses (:ticket:`34539`). + +* Fixed a regression in Django 4.2 that caused a crash of ``QuerySet.defer()`` + when passing a ``ManyToManyField`` or ``GenericForeignKey`` reference. While + doing so is a no-op, it was allowed in older version (:ticket:`34570`). diff --git a/tests/defer_regress/tests.py b/tests/defer_regress/tests.py index 9f94d5fac125..ab2be085c6a7 100644 --- a/tests/defer_regress/tests.py +++ b/tests/defer_regress/tests.py @@ -296,6 +296,12 @@ def test_common_model_different_mask(self): with self.assertNumQueries(1): self.assertEqual(leaf.second_child.value, 64) + def test_defer_many_to_many_ignored(self): + location = Location.objects.create() + request = Request.objects.create(location=location) + with self.assertNumQueries(1): + self.assertEqual(Request.objects.defer("items").get(), request) + class DeferDeletionSignalsTests(TestCase): senders = [Item, Proxy] From 2b5c5e54de6545c6cf3cc97996b37618cbae87bd Mon Sep 17 00:00:00 2001 From: Mariusz Felisiak Date: Wed, 17 May 2023 12:13:10 +0200 Subject: [PATCH 14/47] [4.2.x] Updated broken links in docs. Backport of 93830abf7694e0f281931f10eeaa34993855e7dd from main --- docs/howto/outputting-pdf.txt | 2 +- docs/internals/contributing/writing-code/unit-tests.txt | 2 +- docs/ref/contrib/gis/feeds.txt | 2 +- docs/ref/models/fields.txt | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/howto/outputting-pdf.txt b/docs/howto/outputting-pdf.txt index 11b3fb97a5c3..bcdfa6acc49c 100644 --- a/docs/howto/outputting-pdf.txt +++ b/docs/howto/outputting-pdf.txt @@ -14,7 +14,7 @@ For example, Django was used at kusports.com_ to generate customized, printer-friendly NCAA tournament brackets, as PDF files, for people participating in a March Madness contest. -.. _ReportLab: https://www.reportlab.com/opensource/ +.. _ReportLab: https://docs.reportlab.com/ .. _kusports.com: http://www2.kusports.com/ Install ReportLab diff --git a/docs/internals/contributing/writing-code/unit-tests.txt b/docs/internals/contributing/writing-code/unit-tests.txt index a0b985c8a0fd..2d0ba67144c7 100644 --- a/docs/internals/contributing/writing-code/unit-tests.txt +++ b/docs/internals/contributing/writing-code/unit-tests.txt @@ -292,7 +292,7 @@ dependencies: * :pypi:`pywatchman` * :pypi:`redis` 3.4+ * :pypi:`setuptools` -* :pypi:`memcached`, plus a `supported Python binding +* :pypi:`python-memcached`, plus a `supported Python binding `_ * `gettext `_ (:ref:`gettext_on_windows`) diff --git a/docs/ref/contrib/gis/feeds.txt b/docs/ref/contrib/gis/feeds.txt index d22c728b5ff4..9ae9d4f03a4b 100644 --- a/docs/ref/contrib/gis/feeds.txt +++ b/docs/ref/contrib/gis/feeds.txt @@ -13,7 +13,7 @@ Django's, please consult :doc:`Django's syndication documentation .. _W3C Geo: https://www.w3.org/2003/01/geo/ -__ https://georss.org +__ https://www.ogc.org/standard/georss/ Example ======= diff --git a/docs/ref/models/fields.txt b/docs/ref/models/fields.txt index 7374ea6b6374..139b338460d8 100644 --- a/docs/ref/models/fields.txt +++ b/docs/ref/models/fields.txt @@ -279,7 +279,7 @@ Django provides an ``IntegerChoices`` class. For example:: suit = models.IntegerField(choices=Suit.choices) It is also possible to make use of the `Enum Functional API -`_ with the caveat +`_ with the caveat that labels are automatically generated as highlighted above: .. code-block:: pycon From cdd970ae22303e6c58b5c1f3ba695c470a811b56 Mon Sep 17 00:00:00 2001 From: Mariusz Felisiak Date: Wed, 17 May 2023 13:14:43 +0200 Subject: [PATCH 15/47] [4.2.x] Fixed #34568 -- Made makemigrations --update respect --name option. Thanks David Sanders for the report. Backport of c52f4295f254e1c14af769d22b1a5f516a941f58 from main --- .../management/commands/makemigrations.py | 5 ++-- docs/ref/django-admin.txt | 3 +++ docs/releases/4.2.2.txt | 3 +++ tests/migrations/test_commands.py | 26 +++++++++++++++++++ 4 files changed, 34 insertions(+), 3 deletions(-) diff --git a/django/core/management/commands/makemigrations.py b/django/core/management/commands/makemigrations.py index 284a95409f6b..35661d49972d 100644 --- a/django/core/management/commands/makemigrations.py +++ b/django/core/management/commands/makemigrations.py @@ -316,9 +316,8 @@ def write_to_last_migration_files(self, changes): ) # Update name. previous_migration_path = MigrationWriter(leaf_migration).path - suggested_name = ( - leaf_migration.name[:4] + "_" + leaf_migration.suggest_name() - ) + name_fragment = self.migration_name or leaf_migration.suggest_name() + suggested_name = leaf_migration.name[:4] + f"_{name_fragment}" if leaf_migration.name == suggested_name: new_name = leaf_migration.name + "_updated" else: diff --git a/docs/ref/django-admin.txt b/docs/ref/django-admin.txt index 5e1be0d206d7..1c43523d67ac 100644 --- a/docs/ref/django-admin.txt +++ b/docs/ref/django-admin.txt @@ -759,6 +759,9 @@ generated migration files to ``stdout``. Merges model changes into the latest migration and optimize the resulting operations. +The updated migration will have a generated name. In order to preserve the +previous name, set it using ``--name``. + ``migrate`` ----------- diff --git a/docs/releases/4.2.2.txt b/docs/releases/4.2.2.txt index ca21e5f1ec94..7506b8a2371e 100644 --- a/docs/releases/4.2.2.txt +++ b/docs/releases/4.2.2.txt @@ -19,3 +19,6 @@ Bugfixes * Fixed a regression in Django 4.2 that caused a crash of ``QuerySet.defer()`` when passing a ``ManyToManyField`` or ``GenericForeignKey`` reference. While doing so is a no-op, it was allowed in older version (:ticket:`34570`). + +* Fixed a bug in Django 4.2 where :option:`makemigrations --update` didn't + respect the ``--name`` option (:ticket:`34568`). diff --git a/tests/migrations/test_commands.py b/tests/migrations/test_commands.py index 0117d1e4aa33..cabf0ec71208 100644 --- a/tests/migrations/test_commands.py +++ b/tests/migrations/test_commands.py @@ -2649,6 +2649,32 @@ def test_makemigrations_update_existing_name(self): self.assertNotEqual(initial_content, fp.read()) self.assertIn(f"Deleted {migration_file}", out.getvalue()) + def test_makemigrations_update_custom_name(self): + custom_name = "delete_something" + with self.temporary_migration_module( + module="migrations.test_migrations" + ) as migration_dir: + old_migration_file = os.path.join(migration_dir, "0002_second.py") + with open(old_migration_file) as fp: + initial_content = fp.read() + + with captured_stdout() as out: + call_command( + "makemigrations", "migrations", update=True, name=custom_name + ) + self.assertFalse( + any( + filename.startswith("0003") + for filename in os.listdir(migration_dir) + ) + ) + self.assertIs(os.path.exists(old_migration_file), False) + new_migration_file = os.path.join(migration_dir, f"0002_{custom_name}.py") + self.assertIs(os.path.exists(new_migration_file), True) + with open(new_migration_file) as fp: + self.assertNotEqual(initial_content, fp.read()) + self.assertIn(f"Deleted {old_migration_file}", out.getvalue()) + def test_makemigrations_update_applied_migration(self): recorder = MigrationRecorder(connection) recorder.record_applied("migrations", "0001_initial") From e1c00f8b361bf89deb68733bbc5189734bbcd6b5 Mon Sep 17 00:00:00 2001 From: Simon Charette Date: Sun, 21 May 2023 16:59:56 +0100 Subject: [PATCH 16/47] [4.2.x] Fixed #34580 -- Avoided unnecessary computation of selected expressions in SQLCompiler. Performance regression in 278881e37619278789942513916acafaa88d26f3. Co-authored-by: David Smith Backport of 98f6ada0e2058d67d91fb6c16482411ec2ca0967 from main --- django/db/models/sql/compiler.py | 4 +++- docs/releases/4.2.2.txt | 3 +++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/django/db/models/sql/compiler.py b/django/db/models/sql/compiler.py index 1c16217ae78f..3b438a1de67f 100644 --- a/django/db/models/sql/compiler.py +++ b/django/db/models/sql/compiler.py @@ -331,7 +331,9 @@ def _order_by_pairs(self): default_order, _ = ORDER_DIR["DESC"] selected_exprs = {} - if select := self.select: + # Avoid computing `selected_exprs` if there is no `ordering` as it's + # relatively expensive. + if ordering and (select := self.select): for ordinal, (expr, _, alias) in enumerate(select, start=1): pos_expr = PositionRef(ordinal, alias, expr) if alias: diff --git a/docs/releases/4.2.2.txt b/docs/releases/4.2.2.txt index 7506b8a2371e..475531b53136 100644 --- a/docs/releases/4.2.2.txt +++ b/docs/releases/4.2.2.txt @@ -22,3 +22,6 @@ Bugfixes * Fixed a bug in Django 4.2 where :option:`makemigrations --update` didn't respect the ``--name`` option (:ticket:`34568`). + +* Fixed a performance regression in Django 4.2 when compiling queries without + ordering (:ticket:`34580`). From 6b76481fb968c3d35ee01af38a84d210c0623e62 Mon Sep 17 00:00:00 2001 From: gtleee Date: Mon, 22 May 2023 05:43:15 +0000 Subject: [PATCH 17/47] [4.2.x] Fixed #34588 -- Removed usage of nonexistent stylesheet in the 'Congrats' page. Regression in d46cc15c51219c3418e0287bf018c5ba1346f825. Backport of 0a324f1b66b9b948041b1c557fc18b3fb40743c4 from main --- django/views/templates/default_urlconf.html | 1 - docs/releases/4.2.2.txt | 3 +++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/django/views/templates/default_urlconf.html b/django/views/templates/default_urlconf.html index bdef8b5a0a9e..c54ce842d1e7 100644 --- a/django/views/templates/default_urlconf.html +++ b/django/views/templates/default_urlconf.html @@ -6,7 +6,6 @@ {% translate "The install worked successfully! Congratulations!" %} -