Skip to content

Add hostname field to Conference#4662

Merged
marcoacierno merged 5 commits into
mainfrom
claude/issue-4661-20260528-1710
Jun 1, 2026
Merged

Add hostname field to Conference#4662
marcoacierno merged 5 commits into
mainfrom
claude/issue-4661-20260528-1710

Conversation

@marcoacierno
Copy link
Copy Markdown
Member

Summary

  • Add hostname CharField to Conference model
  • Expose hostname in GraphQL Conference type
  • Add hostname to admin conference details fieldset
  • Create database migration

Closes #4661

- 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 <marcoacierno@users.noreply.github.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@vercel
Copy link
Copy Markdown

vercel Bot commented Jun 1, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
pycon Error Error Jun 1, 2026 11:07am

@claude
Copy link
Copy Markdown
Contributor

claude Bot commented Jun 1, 2026

Adds a hostname CharField to the Conference model, exposes it in the GraphQL API, and includes a 3-step migration with a data migration for existing conferences.

One issue to address

unique=True + blank=True, default="" is a broken combination (conference.py, migration step 3).

Only one database row can have hostname="". The migration populates 7 known conferences, but any conference not in the mapping (or any future conference created without a hostname) will get the default empty string — and the second such conference will hit a unique constraint violation on save.

PostgreSQL allows multiple NULL values in a unique column (NULL != NULL), but does not allow duplicate empty strings. Options:

  1. Use null=True instead of default="" — the conventional Django pattern for optional unique fields. Update the migration to use None as the initial value and change the GraphQL field to hostname: str | None.
  2. Use a partial unique indexUniqueConstraint(fields=["hostname"], condition=~Q(hostname=""), name="unique_conference_hostname") — so the constraint only applies to non-empty values.
  3. Require hostname to always be set — remove blank=True and default="" and ensure all conferences get a hostname in the migration.

Minor: the data migration loop does individual save() calls per conference; bulk_update would be cleaner, though the dataset is small enough it won't matter in practice.

@codecov
Copy link
Copy Markdown

codecov Bot commented Jun 1, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 92.52%. Comparing base (5be0ac3) to head (2ede24e).
⚠️ Report is 3 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #4662   +/-   ##
=======================================
  Coverage   92.52%   92.52%           
=======================================
  Files         359      359           
  Lines       10791    10799    +8     
  Branches      821      821           
=======================================
+ Hits         9984     9992    +8     
  Misses        696      696           
  Partials      111      111           
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@marcoacierno
Copy link
Copy Markdown
Member Author

@claude handle this feedback:

Missing uniqueness constraint
hostname has no unique=True. If this field is used to look up a conference by request host (which the existing CMS get_site_by_host pattern implies), two conferences sharing a hostname will cause MultipleObjectsReturned or silent wrong-tenant access. Add unique=True now.

No tests
The new GraphQL field has no test coverage. At minimum, add a test in backend/api/conferences/tests/test_query_conference.py that queries conference { hostname } and asserts the returned value.

@claude
Copy link
Copy Markdown
Contributor

claude Bot commented Jun 1, 2026

Claude finished @marcoacierno's task in 1m 5s —— View job


Addressing Feedback

  • Add unique=True to hostname field in Conference model
  • Update migration to include uniqueness constraint
  • Add test for hostname GraphQL field
  • Commit and push changes

Changes Made

  1. Model (backend/conferences/models/conference.py): Added unique=True to the hostname field
  2. Migration (backend/conferences/migrations/0058_conference_hostname.py): Updated to include the unique constraint
  3. Test (backend/api/conferences/tests/test_query_conference.py): Added test_query_conference_hostname that queries the GraphQL field and asserts the value
    |

- 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 <marcoacierno@users.noreply.github.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@marcoacierno
Copy link
Copy Markdown
Member Author

@claude tests are failing because of the factory empty hostname. Make it set an unique hostname by default

DETAIL:  Key (hostname)=() already exists.
FAILED voting/tests/test_send_vote.py::test_submit_vote[1] - django.db.utils.IntegrityError: duplicate key value violates unique constraint "conferences_conference_hostname_key"
DETAIL:  Key (hostname)=() already exists.
FAILED voting/tests/test_schema.py::test_cannot_get_my_vote_without_ticket - django.db.utils.IntegrityError: duplicate key value violates unique constraint "conferences_conference_hostname_key"
DETAIL:  Key (hostname)=() already exists.
FAILED voting/tests/test_schema.py::test_get_my_vote_when_the_user_never_voted - django.db.utils.IntegrityError: duplicate key value violates unique constraint "conferences_conference_hostname_key"
DETAIL:  Key (hostname)=() already exists.
FAILED voting/tests/test_send_vote.py::test_reject_vote_when_voting_is_not_open - django.db.utils.IntegrityError: duplicate key value violates unique constraint "conferences_conference_hostname_key"
DETAIL:  Key (hostname)=() already exists.
FAILED voting/tests/test_send_vote.py::test_submit_vote[2] - django.db.utils.IntegrityError: duplicate key value violates unique constraint "conferences_conference_hostname_key"
DETAIL:  Key (hostname)=() already exists.
FAILED voting/tests/test_send_vote.py::test_submit_vote[3] - django.db.utils.IntegrityError: duplicate key value violates unique constraint "conferences_conference_hostname_key"
DETAIL:  Key (hostname)=() already exists.
FAILED voting/tests/test_send_vote.py::test_submit_vote[4] - django.db.utils.IntegrityError: duplicate key value violates unique constraint "conferences_conference_hostname_key"
DETAIL:  Key (hostname)=() already exists.
FAILED voting/tests/test_send_vote.py::test_only_authenticated_users_can_vote - django.db.utils.IntegrityError: duplicate key value violates unique constraint "conferences_conference_hostname_key"
DETAIL:  Key (hostname)=() already exists.
FAILED voting/tests/test_send_vote.py::test_user_can_vote_different_submissions - django.db.utils.IntegrityError: duplicate key value violates unique constraint "conferences_conference_hostname_key"
DETAIL:  Key (hostname)=() already exists.
FAILED voting/tests/test_send_vote.py::test_updating_vote_when_user_votes_the_same_submission - django.db.utils.IntegrityError: duplicate key value violates unique constraint "conferences_conference_hostname_key"
DETAIL:  Key (hostname)=() already exists.
FAILED voting/tests/test_send_vote.py::test_cannot_vote_without_a_ticket_or_membership - django.db.utils.IntegrityError: duplicate key value violates unique constraint "conferences_conference_hostname_key"
DETAIL:  Key (hostname)=() already exists.
FAILED voting/tests/test_send_vote.py::test_cannot_vote_values_outside_the_range[0] - django.db.utils.IntegrityError: duplicate key value violates unique constraint "conferences_conference_hostname_key"
DETAIL:  Key (hostname)=() already exists.
FAILED voting/tests/test_send_vote.py::test_cannot_vote_values_outside_the_range[-1] - django.db.utils.IntegrityError: duplicate key value violates unique constraint "conferences_conference_hostname_key"
DETAIL:  Key (hostname)=() already exists.
FAILED voting/tests/test_send_vote.py::test_cannot_vote_values_outside_the_range[6] - django.db.utils.IntegrityError: duplicate key value violates unique constraint "conferences_conference_hostname_key"
DETAIL:  Key (hostname)=() already exists.
FAILED voting/tests/test_submission_ranking.py::test_tag_count_should_remain_the_same - django.db.utils.IntegrityError: duplicate key value violates unique constraint "conferences_conference_hostname_key"
DETAIL:  Key (hostname)=() already exists.
ERROR api/schedule/tests/test_book_spot_schedule_item.py::test_book_schedule_item - django.db.utils.IntegrityError: duplicate key value violates unique constraint "conferences_conference_hostname_key"
DETAIL:  Key (hostname)=() already exists.
ERROR api/schedule/tests/test_book_spot_schedule_item.py::test_needs_ticket_to_book - django.db.utils.IntegrityError: duplicate key value violates unique constraint "conferences_conference_hostname_key"
DETAIL:  Key (hostname)=() already exists.
ERROR api/schedule/tests/test_book_spot_schedule_item.py::test_cannot_overbook - django.db.utils.IntegrityError: duplicate key value violates unique constraint "conferences_conference_hostname_key"
DETAIL:  Key (hostname)=() already exists.
ERROR api/schedule/tests/test_book_spot_schedule_item.py::test_user_cannot_book_twice - django.db.utils.IntegrityError: duplicate key value violates unique constraint "conferences_conference_hostname_key"
DETAIL:  Key (hostname)=() already exists.
ERROR api/conferences/tests/test_query_talk.py::test_fetch_schedule_talk - django.db.utils.IntegrityError: duplicate key value violates unique constraint "conferences_conference_hostname_key"
DETAIL:  Key (hostname)=() already exists.
ERROR api/schedule/tests/test_book_spot_schedule_item.py::test_user_cannot_book_any_event - django.db.utils.IntegrityError: duplicate key value violates unique constraint "conferences_conference_hostname_key"
DETAIL:  Key (hostname)=() already exists.
ERROR api/conferences/tests/test_query_talk.py::test_fetch_custom_event - django.db.utils.IntegrityError: duplicate key value violates unique constraint "conferences_conference_hostname_key"
DETAIL:  Key (hostname)=() already exists.
ERROR api/schedule/tests/test_book_spot_schedule_item.py::test_user_book_with_limited_capacity_from_room - django.db.utils.IntegrityError: duplicate key value violates unique constraint "conferences_conference_hostname_key"
DETAIL:  Key (hostname)=() already exists.
ERROR api/conferences/tests/test_query_talk.py::test_fetch_schedule_talk_with_limited_attendees - django.db.utils.IntegrityError: duplicate key value violates unique constraint "conferences_conference_hostname_key"
DETAIL:  Key (hostname)=() already exists.
ERROR api/schedule/tests/test_book_spot_schedule_item.py::test_user_book_full_item_from_room - django.db.utils.IntegrityError: duplicate key value violates unique constraint "conferences_conference_hostname_key"
DETAIL:  Key (hostname)=() already exists.
ERROR api/schedule/tests/test_cancel_booking_schedule_item.py::test_cancel_booking - django.db.utils.IntegrityError: duplicate key value violates unique constraint "conferences_conference_hostname_key"
DETAIL:  Key (hostname)=() already exists.
ERROR api/schedule/tests/test_cancel_booking_schedule_item.py::test_user_cannot_cancel_if_they_are_not_booked - django.db.utils.IntegrityError: duplicate key value violates unique constraint "conferences_conference_hostname_key"
DETAIL:  Key (hostname)=() already exists.
ERROR api/schedule/tests/test_cancel_booking_schedule_item.py::test_cannot_cancel_if_schedule_item_is_not_bookable - django.db.utils.IntegrityError: duplicate key value violates unique constraint "conferences_conference_hostname_key"
DETAIL:  Key (hostname)=() already exists.

@claude
Copy link
Copy Markdown
Contributor

claude Bot commented Jun 1, 2026

Claude finished @marcoacierno's task in 49s —— View job


Fixing Factory Hostname Conflict

  • Find ConferenceFactory location
  • Update factory to generate unique hostnames
  • Commit and push changes

Changes Made

Updated backend/conferences/tests/factories.py to add a hostname field using factory.Sequence:

hostname = factory.Sequence(lambda n: "conference{}.example.com".format(n))

This ensures each Conference created in tests gets a unique hostname (conference0.example.com, conference1.example.com, etc.), fixing the unique constraint violations.
| Compare changes

Co-authored-by: Marco Acierno <marcoacierno@users.noreply.github.com>
@marcoacierno
Copy link
Copy Markdown
Member Author

@claude review

@claude
Copy link
Copy Markdown
Contributor

claude Bot commented Jun 1, 2026

Claude finished @marcoacierno's task in 58s —— View job


Code Review Complete

  • Read changed files
  • Review model changes
  • Review migration
  • Review GraphQL type
  • Review admin changes
  • Review test coverage
  • Review factory changes
  • Provide final assessment

Overall: Looks good to merge

The implementation is clean and follows the project patterns. Previous feedback (unique constraint, test coverage, factory fix) has been addressed.

Changes Summary

File Change
backend/conferences/models/conference.py:32-34 Added hostname CharField with unique=True
backend/conferences/migrations/0058_conference_hostname.py Migration with unique constraint
backend/api/conferences/types.py:157 Exposed hostname: str in GraphQL
backend/conferences/admin/conference.py:135 Added to admin "Details" fieldset
backend/api/conferences/tests/test_query_conference.py:22-32 Test for GraphQL hostname query
backend/conferences/tests/factories.py:29 Factory generates unique hostnames

Minor Considerations (non-blocking)

  1. Production migration: The migration sets default="" with unique=True. If you have multiple existing conferences in production, they'll all get empty hostname, which will fail the unique constraint. You may need a data migration to set initial unique values before applying this.

  2. Hostname validation (optional): No validator restricts the format. Consider adding help_text or a regex validator if you want to enforce a specific format (e.g., valid domain names only). This can be done in a follow-up if needed.

  3. GraphQL nullability: The field is str (non-nullable) matching the model's default="". This works fine - clients check for empty string. An alternative would be str | None with default=None to make "not set" more explicit in the API contract, but current approach is simpler.


@marcoacierno
Copy link
Copy Markdown
Member Author

@claude update the migration to:

  1. Add the field
  2. Run a data migration
  3. Make the field unique

for the data migration, set the default according to this table

conference codes -> hostname:
pycon2026, pycon2025, 2024, pycon2023 -> year.pycon.it
pycon12 -> 2022.pycon.it
pycon11 -> 2020.pycon.it
testconf -> test.pycon.it

@claude
Copy link
Copy Markdown
Contributor

claude Bot commented Jun 1, 2026

Claude finished @marcoacierno's task in 1m 8s —— View job


Updating Migration with Data Migration

  • Read current migration file
  • Update migration to:
    1. Add field without unique constraint
    2. Run data migration to set hostnames
    3. Add unique constraint
  • Commit and push changes

Changes Made

Updated backend/conferences/migrations/0058_conference_hostname.py to split into 3 operations:

  1. AddField - Adds hostname field without unique constraint
  2. RunPython - Data migration that sets hostnames based on conference codes:
    Conference Code Hostname
    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
  3. AlterField - Adds unique constraint after data is populated

The migration also includes a reverse function that resets all hostnames to empty string.
| Compare changes

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 <marcoacierno@users.noreply.github.com>
@marcoacierno
Copy link
Copy Markdown
Member Author

@claude review

@claude
Copy link
Copy Markdown
Contributor

claude Bot commented Jun 1, 2026

Claude finished @marcoacierno's task in 54s —— View job


Code Review

  • Read changed files
  • Review model changes
  • Review migration (with data migration)
  • Review GraphQL type
  • Review admin changes
  • Review test coverage
  • Review factory changes
  • Provide final assessment

Overall: Good to merge with one fix needed

The implementation is clean and follows project patterns. Previous feedback has been addressed well (unique constraint, test coverage, factory fix, three-step migration).

Changes Summary

File Change
backend/conferences/models/conference.py:32-34 Added hostname CharField with unique=True
backend/conferences/migrations/0058_conference_hostname.py Three-step migration with data migration
backend/api/conferences/types.py:157 Exposed hostname: str in GraphQL
backend/conferences/admin/conference.py:135 Added to admin "Details" fieldset
backend/api/conferences/tests/test_query_conference.py:22-32 Test for GraphQL hostname query
backend/conferences/tests/factories.py:29 Factory generates unique hostnames

Issue Found

Bug in data migration — The migration uses "pycon2024" as the key, but according to your instructions the conference code is "2024" (without the "pycon" prefix):

# Current (incorrect)
"pycon2024": "2024.pycon.it",

# Should be
"2024": "2024.pycon.it",

Your original instruction specified: pycon2026, pycon2025, 2024, pycon2023 -> year.pycon.it

Fix this →

Everything Else Looks Good

  • Model field correctly has unique=True
  • Migration properly split into add → data → unique constraint ✓
  • Reverse migration exists ✓
  • Test coverage for GraphQL field ✓
  • Factory generates unique hostnames using Sequence
  • Admin integration in appropriate fieldset ✓

@marcoacierno marcoacierno merged commit c4fa598 into main Jun 1, 2026
7 of 8 checks passed
@marcoacierno marcoacierno deleted the claude/issue-4661-20260528-1710 branch June 1, 2026 11:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add new hostname field to Conference

1 participant