From e082616a904e790a5168f2e5f175063234db53c9 Mon Sep 17 00:00:00 2001 From: "claude[bot]" <41898282+claude[bot]@users.noreply.github.com> Date: Thu, 28 May 2026 17:13:29 +0000 Subject: [PATCH 1/5] Add hostname field to Conference model - Add hostname CharField to Conference model with max_length=255 - Expose hostname in GraphQL Conference type - Add hostname to admin conference details fieldset - Create database migration 0058_conference_hostname Closes #4661 Co-authored-by: Marco Acierno Co-Authored-By: Claude Opus 4.5 --- backend/api/conferences/types.py | 1 + backend/conferences/admin/conference.py | 1 + .../migrations/0058_conference_hostname.py | 18 ++++++++++++++++++ backend/conferences/models/conference.py | 1 + 4 files changed, 21 insertions(+) create mode 100644 backend/conferences/migrations/0058_conference_hostname.py diff --git a/backend/api/conferences/types.py b/backend/api/conferences/types.py index 3d898734f6..c75d451ae6 100644 --- a/backend/api/conferences/types.py +++ b/backend/api/conferences/types.py @@ -154,6 +154,7 @@ class Conference: resolver=make_localized_resolver("introduction") ) code: str + hostname: str start: datetime end: datetime map: Map | None = strawberry.field(resolver=resolve_map) diff --git a/backend/conferences/admin/conference.py b/backend/conferences/admin/conference.py index 2d33891ed0..97f03ca148 100644 --- a/backend/conferences/admin/conference.py +++ b/backend/conferences/admin/conference.py @@ -132,6 +132,7 @@ class ConferenceAdmin( "organizer", "name", "code", + "hostname", "logo", "location", "introduction", diff --git a/backend/conferences/migrations/0058_conference_hostname.py b/backend/conferences/migrations/0058_conference_hostname.py new file mode 100644 index 0000000000..e67b2f6562 --- /dev/null +++ b/backend/conferences/migrations/0058_conference_hostname.py @@ -0,0 +1,18 @@ +# Generated by Django 5.1.4 on 2026-05-28 17:12 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('conferences', '0057_add_grants_waiting_list_update_deadline_type'), + ] + + operations = [ + migrations.AddField( + model_name='conference', + name='hostname', + field=models.CharField(blank=True, default='', max_length=255, verbose_name='hostname'), + ), + ] diff --git a/backend/conferences/models/conference.py b/backend/conferences/models/conference.py index 397724f190..8823c980c2 100644 --- a/backend/conferences/models/conference.py +++ b/backend/conferences/models/conference.py @@ -29,6 +29,7 @@ class Conference(GeoLocalizedModel, TimeFramedModel, TimeStampedModel): timezone = TimeZoneField() logo = models.ImageField(_("logo"), upload_to=get_upload_to, blank=True) location = models.TextField(_("location"), max_length=1024, blank=True) + hostname = models.CharField(_("hostname"), max_length=255, blank=True, default="") topics = models.ManyToManyField( "conferences.Topic", verbose_name=_("topics"), blank=True From 85c0235fc2500fa714fc4a11625832c8e74022e9 Mon Sep 17 00:00:00 2001 From: "claude[bot]" <41898282+claude[bot]@users.noreply.github.com> Date: Mon, 1 Jun 2026 10:12:15 +0000 Subject: [PATCH 2/5] Add unique constraint to hostname field and add test - Add unique=True to hostname CharField in Conference model - Update migration to include uniqueness constraint - Add test for hostname GraphQL field query Co-authored-by: Marco Acierno Co-Authored-By: Claude Opus 4.5 --- .../api/conferences/tests/test_query_conference.py | 13 +++++++++++++ .../migrations/0058_conference_hostname.py | 2 +- backend/conferences/models/conference.py | 4 +++- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/backend/api/conferences/tests/test_query_conference.py b/backend/api/conferences/tests/test_query_conference.py index 04a2fb5c53..030d216028 100644 --- a/backend/api/conferences/tests/test_query_conference.py +++ b/backend/api/conferences/tests/test_query_conference.py @@ -19,6 +19,19 @@ def _query_conference(graphql_client, conference): return graphql_client.query(query, variables={"code": conference.code}) +def test_query_conference_hostname(graphql_client): + conference = ConferenceFactory(hostname="pycon.it") + + query = """query($code: String!) { + conference(code: $code) { + hostname + } + }""" + + result = graphql_client.query(query, variables={"code": conference.code}) + assert result["data"]["conference"]["hostname"] == "pycon.it" + + def test_query_conference_current_day(graphql_client): conference = ConferenceFactory() DayFactory(conference=conference, day=timezone.datetime(2020, 10, 10)) diff --git a/backend/conferences/migrations/0058_conference_hostname.py b/backend/conferences/migrations/0058_conference_hostname.py index e67b2f6562..e2b8e1eacb 100644 --- a/backend/conferences/migrations/0058_conference_hostname.py +++ b/backend/conferences/migrations/0058_conference_hostname.py @@ -13,6 +13,6 @@ class Migration(migrations.Migration): migrations.AddField( model_name='conference', name='hostname', - field=models.CharField(blank=True, default='', max_length=255, verbose_name='hostname'), + field=models.CharField(blank=True, default='', max_length=255, unique=True, verbose_name='hostname'), ), ] diff --git a/backend/conferences/models/conference.py b/backend/conferences/models/conference.py index 8823c980c2..07e64066b4 100644 --- a/backend/conferences/models/conference.py +++ b/backend/conferences/models/conference.py @@ -29,7 +29,9 @@ class Conference(GeoLocalizedModel, TimeFramedModel, TimeStampedModel): timezone = TimeZoneField() logo = models.ImageField(_("logo"), upload_to=get_upload_to, blank=True) location = models.TextField(_("location"), max_length=1024, blank=True) - hostname = models.CharField(_("hostname"), max_length=255, blank=True, default="") + hostname = models.CharField( + _("hostname"), max_length=255, blank=True, default="", unique=True + ) topics = models.ManyToManyField( "conferences.Topic", verbose_name=_("topics"), blank=True From e872ee732fdaefea9ba3bdaa108522dce0e046c3 Mon Sep 17 00:00:00 2001 From: "claude[bot]" <41898282+claude[bot]@users.noreply.github.com> Date: Mon, 1 Jun 2026 10:32:03 +0000 Subject: [PATCH 3/5] Fix ConferenceFactory to generate unique hostnames Co-authored-by: Marco Acierno --- backend/conferences/tests/factories.py | 1 + 1 file changed, 1 insertion(+) diff --git a/backend/conferences/tests/factories.py b/backend/conferences/tests/factories.py index 9946f9f50e..da73d2394b 100644 --- a/backend/conferences/tests/factories.py +++ b/backend/conferences/tests/factories.py @@ -26,6 +26,7 @@ class ConferenceFactory(DjangoModelFactory): organizer = factory.SubFactory(OrganizerFactory) name = LanguageFactory("name") code = factory.Sequence(lambda n: "code{}".format(n)) + hostname = factory.Sequence(lambda n: "conference{}.example.com".format(n)) introduction = LanguageFactory("sentence") start = factory.Faker("past_datetime", tzinfo=UTC) From 136dd9d64d10bc39f63008c00f13828765e0c110 Mon Sep 17 00:00:00 2001 From: "claude[bot]" <41898282+claude[bot]@users.noreply.github.com> Date: Mon, 1 Jun 2026 10:53:59 +0000 Subject: [PATCH 4/5] Add data migration to set conference hostnames Split migration into 3 steps: 1. Add hostname field without unique constraint 2. Run data migration to set hostnames based on conference codes 3. Add unique constraint Hostname mapping: - pycon2026, pycon2025, 2024, pycon2023 -> year.pycon.it - pycon12 -> 2022.pycon.it - pycon11 -> 2020.pycon.it - testconf -> test.pycon.it Co-authored-by: Marco Acierno --- .../migrations/0058_conference_hostname.py | 52 +++++++++++++++++-- 1 file changed, 48 insertions(+), 4 deletions(-) diff --git a/backend/conferences/migrations/0058_conference_hostname.py b/backend/conferences/migrations/0058_conference_hostname.py index e2b8e1eacb..fd4cafd45f 100644 --- a/backend/conferences/migrations/0058_conference_hostname.py +++ b/backend/conferences/migrations/0058_conference_hostname.py @@ -3,16 +3,60 @@ from django.db import migrations, models +def set_conference_hostnames(apps, schema_editor): + Conference = apps.get_model("conferences", "Conference") + + hostname_mapping = { + "pycon2026": "2026.pycon.it", + "pycon2025": "2025.pycon.it", + "2024": "2024.pycon.it", + "pycon2023": "2023.pycon.it", + "pycon12": "2022.pycon.it", + "pycon11": "2020.pycon.it", + "testconf": "test.pycon.it", + } + + for conference in Conference.objects.all(): + if conference.code in hostname_mapping: + conference.hostname = hostname_mapping[conference.code] + conference.save(update_fields=["hostname"]) + + +def reverse_set_conference_hostnames(apps, schema_editor): + Conference = apps.get_model("conferences", "Conference") + Conference.objects.all().update(hostname="") + + class Migration(migrations.Migration): dependencies = [ - ('conferences', '0057_add_grants_waiting_list_update_deadline_type'), + ("conferences", "0057_add_grants_waiting_list_update_deadline_type"), ] operations = [ + # Step 1: Add the field without unique constraint migrations.AddField( - model_name='conference', - name='hostname', - field=models.CharField(blank=True, default='', max_length=255, unique=True, verbose_name='hostname'), + model_name="conference", + name="hostname", + field=models.CharField( + blank=True, default="", max_length=255, verbose_name="hostname" + ), + ), + # Step 2: Run data migration to set hostnames + migrations.RunPython( + set_conference_hostnames, + reverse_set_conference_hostnames, + ), + # Step 3: Add unique constraint + migrations.AlterField( + model_name="conference", + name="hostname", + field=models.CharField( + blank=True, + default="", + max_length=255, + unique=True, + verbose_name="hostname", + ), ), ] From 2ede24e5888ad67c36d311c3b9a6467b090a7ca2 Mon Sep 17 00:00:00 2001 From: Marco Acierno Date: Mon, 1 Jun 2026 13:07:22 +0200 Subject: [PATCH 5/5] Update hostname mapping for conference 2024 --- backend/conferences/migrations/0058_conference_hostname.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/conferences/migrations/0058_conference_hostname.py b/backend/conferences/migrations/0058_conference_hostname.py index fd4cafd45f..063eb0241f 100644 --- a/backend/conferences/migrations/0058_conference_hostname.py +++ b/backend/conferences/migrations/0058_conference_hostname.py @@ -9,7 +9,7 @@ def set_conference_hostnames(apps, schema_editor): hostname_mapping = { "pycon2026": "2026.pycon.it", "pycon2025": "2025.pycon.it", - "2024": "2024.pycon.it", + "pycon2024": "2024.pycon.it", "pycon2023": "2023.pycon.it", "pycon12": "2022.pycon.it", "pycon11": "2020.pycon.it",