From 8815ca4d44c215203feac29e22907406bbd03092 Mon Sep 17 00:00:00 2001 From: Marco Acierno Date: Sun, 8 Nov 2026 18:34:51 +0100 Subject: [PATCH 1/3] Upgrade Django to 6.1.3 Django 6.1 forces a few companion upgrades: - wagtail 7.3.4 -> 8.1: Wagtail 7.3 and 7.4 LTS only support up to Django 6.0; 8.x is the first line supporting 6.1. - wagtail-localize 1.13 -> 1.14.5 for Wagtail 8 / Django 6.1 support. - django-timezone-field 7.0 -> 7.2.2: 7.0 pins Django<6.0. - django-autocomplete-light 3.9.4 -> 4.0.3: 3.9.4 imports django.utils.itercompat, removed in Django 6.0. - django-ses 4.1.1 -> 4.9.0: Django 6.1 support landed in 4.8.0. Add django.contrib.postgres to INSTALLED_APPS: Django 6 raises postgres.E005 for wagtailsearch's SearchVectorField/GinIndex otherwise. Bump the CI postgres service from 14.5 to 18.6 (matching docker-compose; prod RDS runs 18.3): Django 6.1 refuses to connect to PostgreSQL < 15. --- .github/workflows/backend-test.yml | 2 +- .github/workflows/claude.yml | 2 +- backend/pycon/settings/base.py | 1 + backend/pyproject.toml | 12 ++-- backend/uv.lock | 88 ++++++++++++++++++++---------- 5 files changed, 67 insertions(+), 38 deletions(-) diff --git a/.github/workflows/backend-test.yml b/.github/workflows/backend-test.yml index 14d26bee1d..e59ed315bf 100644 --- a/.github/workflows/backend-test.yml +++ b/.github/workflows/backend-test.yml @@ -19,7 +19,7 @@ jobs: services: postgres: - image: postgres:14.5 + image: postgres:18.6 env: POSTGRES_USER: postgres POSTGRES_PASSWORD: postgres diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml index 4d0b051039..d02405a335 100644 --- a/.github/workflows/claude.yml +++ b/.github/workflows/claude.yml @@ -34,7 +34,7 @@ jobs: services: postgres: - image: postgres:14.5 + image: postgres:18.6 env: POSTGRES_USER: postgres POSTGRES_PASSWORD: postgres diff --git a/backend/pycon/settings/base.py b/backend/pycon/settings/base.py index a9250d4d8a..cf08e3c0f0 100644 --- a/backend/pycon/settings/base.py +++ b/backend/pycon/settings/base.py @@ -88,6 +88,7 @@ "django.contrib.sessions", "django.contrib.messages", "django.contrib.staticfiles", + "django.contrib.postgres", "api.apps.ApiConfig", "timezone_field", "strawberry.django", diff --git a/backend/pyproject.toml b/backend/pyproject.toml index c108a976c9..e5165d46d0 100644 --- a/backend/pyproject.toml +++ b/backend/pyproject.toml @@ -43,10 +43,10 @@ known-first-party = [ [project] requires-python = ">=3.14.7" dependencies = [ - "django==5.2.18", + "django==6.1.3", "django-environ==0.14.0", "django-model-utils==5.0.0", - "django-timezone-field==7.0", + "django-timezone-field==7.2.2", "certifi==2026.10.23", "chardet==5.2.0", "idna==3.15", @@ -61,9 +61,9 @@ dependencies = [ "boto3==1.43.34", "pycountry<20.0,>=19.8", "countries<1.0.0,>=0.2.0", - "django-ses==4.1.1", + "django-ses==4.9.0", "hashids<2.0.0,>=1.2.0", - "django-autocomplete-light==3.9.4", + "django-autocomplete-light==4.0.3", "django-queryinspect<2.0.0,>=1.1.0", "lxml==6.1.0", "unidecode<2.0.0,>=1.1.1", @@ -82,8 +82,8 @@ dependencies = [ "stripe==10.5.0", "djangorestframework==3.18.3", "l18n<2022.0,>=2021.3", - "wagtail==7.3.4", - "wagtail-localize==1.13", + "wagtail==8.1", + "wagtail-localize==1.14.5", "celery==5.6.3", "wagtail-headless-preview==0.8.0", "Jinja2>=3.1.6", diff --git a/backend/uv.lock b/backend/uv.lock index 5c2a60a879..13aa88cd8c 100644 --- a/backend/uv.lock +++ b/backend/uv.lock @@ -382,8 +382,8 @@ requires-dist = [ { name = "countries", specifier = ">=0.2.0,<1.0.0" }, { name = "cryptography", specifier = ">=50.0.0" }, { name = "dal-admin-filters", specifier = "==1.1.0" }, - { name = "django", specifier = "==5.2.18" }, - { name = "django-autocomplete-light", specifier = "==3.9.4" }, + { name = "django", specifier = "==6.1.3" }, + { name = "django-autocomplete-light", specifier = "==4.0.3" }, { name = "django-environ", specifier = "==0.14.0" }, { name = "django-imagekit", specifier = "==6.0.0" }, { name = "django-import-export", extras = ["all"], specifier = ">=4.4.4,<5.0.0" }, @@ -391,9 +391,9 @@ requires-dist = [ { name = "django-model-utils", specifier = "==5.0.0" }, { name = "django-ordered-model", specifier = "==3.5" }, { name = "django-queryinspect", specifier = ">=1.1.0,<2.0.0" }, - { name = "django-ses", specifier = "==4.1.1" }, + { name = "django-ses", specifier = "==4.9.0" }, { name = "django-storages", specifier = "==1.14.6" }, - { name = "django-timezone-field", specifier = "==7.0" }, + { name = "django-timezone-field", specifier = "==7.2.2" }, { name = "djangorestframework", specifier = "==3.18.3" }, { name = "google-api-python-client", specifier = ">=2.94.0,<3.0.0" }, { name = "google-auth", specifier = ">=2.22.0,<3.0.0" }, @@ -432,10 +432,10 @@ requires-dist = [ { name = "unidecode", specifier = ">=1.1.1,<2.0.0" }, { name = "urllib3", specifier = "==2.8.0" }, { name = "uwsgi", specifier = "==2.0.30" }, - { name = "wagtail", specifier = "==7.3.4" }, + { name = "wagtail", specifier = "==8.1" }, { name = "wagtail-factories", specifier = "==4.4.0" }, { name = "wagtail-headless-preview", specifier = "==0.8.0" }, - { name = "wagtail-localize", specifier = "==1.13" }, + { name = "wagtail-localize", specifier = "==1.14.5" }, { name = "weasyprint", specifier = ">=68.0" }, { name = "werkzeug", specifier = ">=1.0.1,<4.0.0" }, { name = "whitenoise", specifier = "==6.12.0" }, @@ -1053,16 +1053,16 @@ wheels = [ [[package]] name = "django" -version = "5.2.18" +version = "6.1.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "asgiref" }, { name = "sqlparse" }, { name = "tzdata", marker = "sys_platform == 'win32'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/85/fe/79e692b430c7721bf4b812c328bfe687e73e3f28f56611a6a18a97e887cc/django-5.2.18.tar.gz", hash = "sha256:461c5dd06d2ea16bd5ca37d3f46e4def1d6b0fe7588c6f4e2119517bb0af8b2d", size = 10910238, upload-time = "2026-10-06T13:01:09.371Z" } +sdist = { url = "https://files.pythonhosted.org/packages/55/79/49a609ea76ec51404b482932e33f1e6858946b920232c11b11a25bea3032/django-6.1.3.tar.gz", hash = "sha256:b5d2d9e35295065d13b1927b3f19a59bd119f737aa6299def14ccca1ae3c8c0d", size = 11306257, upload-time = "2026-11-03T15:21:26.142Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d6/01/6568ec52b26548ca1b83d33249f7274db3bf74698f42c0da42ec9db1a24a/django-5.2.18-py3-none-any.whl", hash = "sha256:92ed81d500be6408ecd704d7bd1366c534f30427bffcc63c5fefb129561aec7c", size = 8316071, upload-time = "2026-10-06T13:01:04.413Z" }, + { url = "https://files.pythonhosted.org/packages/77/f2/adbe0352c6673f7b608724be5f69962c80ba1d06f8ed60fa4bfbec258b08/django-6.1.3-py3-none-any.whl", hash = "sha256:a0530e3fdac55d34ccc5893c36f6c57d7a7083064f3d414537e51473648b3290", size = 8424610, upload-time = "2026-11-03T15:21:19.64Z" }, ] [[package]] @@ -1079,12 +1079,15 @@ wheels = [ [[package]] name = "django-autocomplete-light" -version = "3.9.4" +version = "4.0.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "six" }, + { name = "django" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b3/5d/0f1f1884cfa5665a20a89497c80fc10726f47d982905c8e36e9ef31cc7e6/django_autocomplete_light-4.0.3.tar.gz", hash = "sha256:1b0dc31aee64cc084358129df60954c05ab7132657873eebc0612e3160307057", size = 99685, upload-time = "2026-06-18T11:55:02.581Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/22/fa/299a37e7a4baf7bec9c002e4bd1f46cc6e5db8565d8f9883407d471cf2df/django_autocomplete_light-4.0.3-py3-none-any.whl", hash = "sha256:e36a7c570f914cfd793568eea3eb2646da4b64f6d1cd3bea8878cc8b20a18f3f", size = 113477, upload-time = "2026-06-18T11:55:00.869Z" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ae/72/6a6c2d4b05296c9248a1e95430fa4f4605c210c2fac1d7d80d9e7bdf90f0/django-autocomplete-light-3.9.4.tar.gz", hash = "sha256:0f6da75c1c7186698b867a467a8cdb359f0513fdd8e09288a0c2fb018ae3d94e", size = 168936, upload-time = "2022-03-15T08:44:50.603Z" } [[package]] name = "django-debug-toolbar" @@ -1190,6 +1193,19 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/cd/57/cdcdea9a56d114e9217d52ce9a8af19ad7fe8a0996faf8480d3f286c02e0/django_modelcluster-6.5-py3-none-any.whl", hash = "sha256:469b380a294027d5211d0e5d5746e0381f445b058d2229977a58fe0f1c58a596", size = 29865, upload-time = "2026-05-01T12:25:31.886Z" }, ] +[[package]] +name = "django-ninja" +version = "1.8.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "django" }, + { name = "pydantic" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/8d/53/3453836e6246b5d4b0e55c36d2dfab4cad6091d08483bdc4505906a1197c/django_ninja-1.8.0.tar.gz", hash = "sha256:0f043a1aebd2c45e2a124a83e5bd0961491b18cdf81ea57c6abd80607b2c6ef8", size = 2347023, upload-time = "2026-11-08T10:52:03.703Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f1/d5/fbfdae4ab7a81f4980cec09ef17f86d4ac2d96058787bd6282d775be91bc/django_ninja-1.8.0-py3-none-any.whl", hash = "sha256:132f37a36ac5ec9569fdc141da6984c1806bdd08af36f855980fab6cdcb10038", size = 2382930, upload-time = "2026-11-08T10:52:01.541Z" }, +] + [[package]] name = "django-ordered-model" version = "3.5" @@ -1222,15 +1238,15 @@ sdist = { url = "https://files.pythonhosted.org/packages/77/bb/6cb5fb15f27312660 [[package]] name = "django-ses" -version = "4.1.1" +version = "4.9.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "boto3" }, { name = "django" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/80/aa/d0237d9b093c1d671b8c8c7e498c9526af47cc7f4fa7cfc1dc22cb1179c8/django_ses-4.1.1.tar.gz", hash = "sha256:28f9931df1251660eaf976b7413a42e7b0d25a18043316b96c721d8add7bf7b8", size = 47491, upload-time = "2024-08-22T18:26:40.206Z" } +sdist = { url = "https://files.pythonhosted.org/packages/b4/17/b116bb293964d54406b9d4337514f8053886eb66bbb42958286135ae71cd/django_ses-4.9.0.tar.gz", hash = "sha256:d1aa855d8415bb9991fc1fa427dd31a5bb55b98e27c1b19b973566b70a6e83dd", size = 79421, upload-time = "2026-10-29T23:59:48.57Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/4e/6a/de24558d93fe778a8d98bcf3817fa535011250f35ce95d5add7b739bd441/django_ses-4.1.1-py3-none-any.whl", hash = "sha256:83bb09d2b149dbc1a67a89f66a6681a99e32b8253f47ff4b7fae241d05344cc8", size = 29543, upload-time = "2024-08-22T18:26:37.859Z" }, + { url = "https://files.pythonhosted.org/packages/2c/b9/28547a2f22e3ee3d5db1b3935462df2e4a62f9fb48fc01f0d111bc0ec424/django_ses-4.9.0-py3-none-any.whl", hash = "sha256:34e9f6f13b3ebd8618cfd8d9f93d75f40d6dc5a896a1b3ffa48c4054be75fbe5", size = 40891, upload-time = "2026-10-29T23:59:46.923Z" }, ] [[package]] @@ -1286,14 +1302,14 @@ wheels = [ [[package]] name = "django-timezone-field" -version = "7.0" +version = "7.2.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "django" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/94/b3/992aa517b95f2e6934aa05b8160cf55f91c49c7b91e33076ea9af2f29920/django_timezone_field-7.0.tar.gz", hash = "sha256:aa6f4965838484317b7f08d22c0d91a53d64e7bbbd34264468ae83d4023898a7", size = 13683, upload-time = "2024-07-07T18:32:06.941Z" } +sdist = { url = "https://files.pythonhosted.org/packages/12/0b/22654abc2355f3b84e3e5b9d26569639c15d04b96d7186f3a477ec45c1ef/django_timezone_field-7.2.2.tar.gz", hash = "sha256:a004d0b19fe10bf5964cb21a65b36324b16a61879e4711c0dafdf8d6253e8ebc", size = 13158, upload-time = "2026-06-06T05:28:23.638Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/2a/f9/11769c4414026f1a9ce3e581731d07b084683fc7b4c580703dc71ef81347/django_timezone_field-7.0-py3-none-any.whl", hash = "sha256:3232e7ecde66ba4464abb6f9e6b8cc739b914efb9b29dc2cf2eee451f7cc2acb", size = 13161, upload-time = "2024-07-07T18:32:04.639Z" }, + { url = "https://files.pythonhosted.org/packages/2b/5f/c8dfb67105c4ef391a3e9d0bcd35b7eae4c4c9d023d612c3999ae1cb32ef/django_timezone_field-7.2.2-py3-none-any.whl", hash = "sha256:30354d0f37462a0b9b5c289e271580a6be9b58dea30e7bf88435372882c8fa7a", size = 13322, upload-time = "2026-06-06T05:28:22.454Z" }, ] [[package]] @@ -1322,11 +1338,11 @@ wheels = [ [[package]] name = "draftjs-exporter" -version = "5.2.0" +version = "7.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/4f/61/8b7fab482ef246f931b57f55f370e68377a53dcf5259f3fcf01e4889d4af/draftjs_exporter-5.2.0.tar.gz", hash = "sha256:4d665f8c75fd173d2c99326405300e8defcf4961b9b2f16ff117486489c6760b", size = 19674, upload-time = "2026-01-02T14:19:38.17Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a5/cd/f6e8e34690eccd80e551b39a64e81ce22a1b82422a4384d346ba8c1d5b45/draftjs_exporter-7.3.1.tar.gz", hash = "sha256:557e2afb861f9447c8d503089ec140e45e1bbfb4acdce745e589291f117dac93", size = 60638, upload-time = "2026-10-20T07:03:58.069Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/53/e1/2f81aa30ba22ceabb6779ed5dbd6b27fbf6f28deabad91140d1a32f3da5b/draftjs_exporter-5.2.0-py3-none-any.whl", hash = "sha256:f5255510a9c1de60807c1ba4be9666fb44ba263841b63329c8ce70d66146764c", size = 26251, upload-time = "2026-01-02T14:19:36.843Z" }, + { url = "https://files.pythonhosted.org/packages/5e/b3/91c4b92c67afbc70856911467ec6d239e5f0fa0f91974b7a415f168f29fb/draftjs_exporter-7.3.1-py3-none-any.whl", hash = "sha256:eddd07ee418c5f85c6a2900887fa1eb50de0c5f6533193497b1fe063803210e9", size = 75306, upload-time = "2026-10-20T07:03:56.69Z" }, ] [[package]] @@ -2244,15 +2260,15 @@ wheels = [ [[package]] name = "modelsearch" -version = "1.2.2" +version = "1.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "django" }, { name = "django-tasks" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a2/7f/f775ea3ea2180a39fda4fb9bcce634478fc844ab0f436b899cc0a6e7a1c6/modelsearch-1.2.2.tar.gz", hash = "sha256:59fc29965d5411d607d0d5f80a65f0f49bec54bd5a425e8e0bfb185f04761e5b", size = 91157, upload-time = "2026-04-27T23:36:56.311Z" } +sdist = { url = "https://files.pythonhosted.org/packages/77/e3/5ce9c70828fe46be161781a04860fe3fe9d54c9b0b09539d9c291d15dbcf/modelsearch-1.3.2.tar.gz", hash = "sha256:52ede0f65e91efdb9d715f603e0bb3db96a95c80eba695abcd4628c03759999e", size = 105253, upload-time = "2026-08-11T14:38:12.199Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d3/03/24e5c5af6962e85fddebb58ba8448109789f62fee61b8375161284aa8e33/modelsearch-1.2.2-py3-none-any.whl", hash = "sha256:fd18522c1619e00452266513a78284a4e5016871c107036b078a45e42fa871e2", size = 111491, upload-time = "2026-04-27T23:36:54.712Z" }, + { url = "https://files.pythonhosted.org/packages/6a/46/394e799ff69475093f05187929618b13cb230e9e9ce358313a1055724a5d/modelsearch-1.3.2-py3-none-any.whl", hash = "sha256:8738ad7dc6fd2f70f622e717c52fbdcc60285e6b74acc41a7bf3fe911718532b", size = 129677, upload-time = "2026-08-11T14:38:10.768Z" }, ] [[package]] @@ -3773,6 +3789,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/63/8a/677210793a870dd399f0fbdd0b67085b11681a5d5f5c2b020248ac9df790/stripe-10.5.0-py2.py3-none-any.whl", hash = "sha256:682399995c27cb1dbfecda11f85b1ff3bd96a11a689419bf6156075cd7823099", size = 1541397, upload-time = "2024-07-25T21:06:58.559Z" }, ] +[[package]] +name = "swapper" +version = "1.5.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c2/3e/a28d29aa28570b09257dad52cc5e5ebda9fe8802eeca0d9e254ccf8e5788/swapper-1.5.0.tar.gz", hash = "sha256:405f934265aa0c8d8b8e6b1be584875d1a3b7de6b1cd6f47367a4dbdc028609a", size = 24119, upload-time = "2026-09-01T21:51:07.192Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/29/5f/eab0a39f9c16c5d32c00f1f9b7ee9e8823686d1fd40a7fd1f0fc3247a59c/swapper-1.5.0-py2.py3-none-any.whl", hash = "sha256:67ae5a01bc12159dede567b98212a83baa53aa466a8eb5cf44af226b8219d21c", size = 7273, upload-time = "2026-09-01T21:51:05.953Z" }, +] + [[package]] name = "sympy" version = "1.14.0" @@ -4137,7 +4162,7 @@ wheels = [ [[package]] name = "wagtail" -version = "7.3.4" +version = "8.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyascii" }, @@ -4145,6 +4170,7 @@ dependencies = [ { name = "django" }, { name = "django-filter" }, { name = "django-modelcluster" }, + { name = "django-ninja" }, { name = "django-permissionedforms" }, { name = "django-taggit" }, { name = "django-tasks" }, @@ -4155,13 +4181,15 @@ dependencies = [ { name = "modelsearch" }, { name = "openpyxl" }, { name = "pillow" }, + { name = "pydantic" }, { name = "requests" }, + { name = "swapper" }, { name = "telepath" }, { name = "willow", extra = ["heif"] }, ] -sdist = { url = "https://files.pythonhosted.org/packages/00/3f/5731e6010db528b5e4da201e65f67703c89770e5be6be49b5a1ea4c42876/wagtail-7.3.4.tar.gz", hash = "sha256:30816255dfbb97238050a6687f04b2b4eb88f5201993c48df36d68fab0a70505", size = 6897983, upload-time = "2026-08-20T15:28:10.932Z" } +sdist = { url = "https://files.pythonhosted.org/packages/7f/f4/b610c5f9e26b43fc404045800a2a3d167e2b055e69837f4ebf3331f78c07/wagtail-8.1.tar.gz", hash = "sha256:5c1abb0e11efc31454db0b5312d6786b5d8fdfbef5c815b7d8bacb2ad6bd486c", size = 7073619, upload-time = "2026-11-02T15:58:35.52Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/4e/63/c34864d49075491157c5215a827406b5663d6025710b3eea00b99592f791/wagtail-7.3.4-py3-none-any.whl", hash = "sha256:2eab9f6a872b967a55f2575a38b4f83a3d406a34d5dab456e0a21c91fd57bcca", size = 9492859, upload-time = "2026-08-20T15:28:00.066Z" }, + { url = "https://files.pythonhosted.org/packages/15/9d/76d9a648ae7fe34425b474be23d9e0bef43f2f332d848a0d2e865c042564/wagtail-8.1-py3-none-any.whl", hash = "sha256:dd7c988377ec6b8fcbd9ea8b5e36d34d800706bb70f927711ff4575619752d42", size = 9756355, upload-time = "2026-11-02T15:57:51.495Z" }, ] [[package]] @@ -4191,7 +4219,7 @@ wheels = [ [[package]] name = "wagtail-localize" -version = "1.13" +version = "1.14.5" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "django" }, @@ -4199,9 +4227,9 @@ dependencies = [ { name = "typing-extensions" }, { name = "wagtail" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/6c/19/781b910e3ee3b1f955376efe92c6f192e8e43130dd2ec892592aaac27073/wagtail_localize-1.13.tar.gz", hash = "sha256:48ecfcd6d002009697b84d77ebcb042451a68da916a1f5ca0e161b472c2b74c8", size = 285949, upload-time = "2026-01-25T16:46:42.592Z" } +sdist = { url = "https://files.pythonhosted.org/packages/50/09/edc4a6a17edcdf78d2a5bf8395e68f991c709d101aad0ce4fc636b0f9ef0/wagtail_localize-1.14.5.tar.gz", hash = "sha256:7e21bb845bd0142a554a8ddb5819450782107dac94756a90f56085991a4c318d", size = 1189851, upload-time = "2026-08-19T15:11:22.001Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/27/ab/18535934b8503000ef0bcd892f505f728a44cbb9499ae3d4e052647e1ef9/wagtail_localize-1.13-py3-none-any.whl", hash = "sha256:48296cb90eb3317bea62ecd5f23cc57088c9c9d39aca3b2261e4f19fa15de2cf", size = 511068, upload-time = "2026-01-25T16:46:40.628Z" }, + { url = "https://files.pythonhosted.org/packages/27/64/59c70f0c48e37bcec2706963adbe5a577e178bdf56790f10e581ffff8f35/wagtail_localize-1.14.5-py3-none-any.whl", hash = "sha256:c08841d1d982e238b4cf5fb8e5d4cace82cf8e8d255fd0db4fa11dd874d7c0fd", size = 535341, upload-time = "2026-08-19T15:11:20.441Z" }, ] [[package]] From 6570a348cfdd9c65dd6c08a8a15d6b624bbe626f Mon Sep 17 00:00:00 2001 From: Marco Acierno Date: Sun, 8 Nov 2026 19:00:41 +0100 Subject: [PATCH 2/3] Fix vote admin changelist crash with Django 6.1 dal_admin_filters calls the FK descriptor's get_queryset() with no arguments, but Django 6 requires the `instance` keyword argument, so /admin/voting/vote/ raised a TypeError. dal-admin-filters 1.1.0 is the latest release, so resolve the queryset from the model field instead. --- backend/voting/admin.py | 5 +++++ backend/voting/tests/test_admin.py | 17 +++++++++++++++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/backend/voting/admin.py b/backend/voting/admin.py index 6592517d89..9f7ed97962 100644 --- a/backend/voting/admin.py +++ b/backend/voting/admin.py @@ -16,6 +16,11 @@ class SubmissionFilter(AutocompleteFilter): field_name = "submission" autocomplete_url = "submission-autocomplete" + def get_queryset_for_field(self, model, name): + # dal_admin_filters calls the FK descriptor's get_queryset() without the + # `instance` argument Django requires. + return model._meta.get_field(name).related_model._base_manager.all() + class ConferenceFilter(AutocompleteFilter): title = "Conference" diff --git a/backend/voting/tests/test_admin.py b/backend/voting/tests/test_admin.py index e620baa175..a5061d2ef1 100644 --- a/backend/voting/tests/test_admin.py +++ b/backend/voting/tests/test_admin.py @@ -1,13 +1,26 @@ import pytest +from django.contrib import admin from i18n.strings import LazyI18nString -from voting.admin import RankSubmissionResource -from voting.models import RankSubmission +from voting.admin import RankSubmissionResource, VoteAdmin +from voting.models import RankSubmission, Vote from voting.tests.factories.ranking import RankSubmissionFactory +from voting.tests.factories.vote import VoteFactory pytestmark = pytest.mark.django_db +def test_vote_changelist_filters_by_submission(rf, admin_superuser): + vote = VoteFactory() + VoteFactory() + request = rf.get("/", {"submission__id__exact": vote.submission_id}) + request.user = admin_superuser + + changelist = VoteAdmin(Vote, admin.site).get_changelist_instance(request) + + assert list(changelist.queryset) == [vote] + + def test_rank_submission_export_includes_submission_title(): RankSubmissionFactory(submission__title=LazyI18nString({"en": "My talk"})) From e3e4252017e85f85c9bc78662ed0395ddcfe4ec3 Mon Sep 17 00:00:00 2001 From: Marco Acierno Date: Mon, 9 Nov 2026 03:00:44 +0100 Subject: [PATCH 3/3] Fix "mark speakers to receive vouchers" admin action on Django 6.1 Django 6.1's changelist applies select_related() with the related fields from list_display instead of an unrestricted select_related(). Calling .only("conference_id") on that queryset defers `submission` while it is still being traversed, so the action raised FieldError from the admin. The test now runs the action on the changelist queryset, which is what the admin passes to it. --- backend/schedule/admin.py | 2 +- backend/schedule/tests/test_admin.py | 11 ++++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/backend/schedule/admin.py b/backend/schedule/admin.py index 8da7259a46..9b612b47c9 100644 --- a/backend/schedule/admin.py +++ b/backend/schedule/admin.py @@ -64,7 +64,7 @@ def mark_speakers_to_receive_vouchers(modeladmin, request, queryset): .distinct() ) - conference = queryset.only("conference_id").first().conference + conference = queryset.first().conference existing_vouchers: dict[int, ConferenceVoucher.VoucherType] = { user_id: voucher_type diff --git a/backend/schedule/tests/test_admin.py b/backend/schedule/tests/test_admin.py index d571f8a921..0a3a2c263a 100644 --- a/backend/schedule/tests/test_admin.py +++ b/backend/schedule/tests/test_admin.py @@ -27,7 +27,7 @@ pytestmark = pytest.mark.django_db -def test_mark_speakers_to_receive_vouchers(rf, mocker): +def test_mark_speakers_to_receive_vouchers(rf, mocker, admin_superuser): mocker.patch( "conferences.models.conference_voucher.get_random_string", side_effect=[ @@ -54,11 +54,16 @@ def test_mark_speakers_to_receive_vouchers(rf, mocker): conference=conference, submission=None, ) + request = rf.get("/") + request.user = admin_superuser + changelist = ScheduleItemAdmin(ScheduleItem, AdminSite()).get_changelist_instance( + request + ) mark_speakers_to_receive_vouchers( None, - request=rf.get("/"), - queryset=ScheduleItem.objects.filter(conference=conference), + request=request, + queryset=changelist.get_queryset(request).filter(conference=conference), ) assert ConferenceVoucher.objects.count() == 2