From 8374d2a1f704c7bb4da60829f7b06960cd104ef4 Mon Sep 17 00:00:00 2001 From: Maxim Burgerhout Date: Sun, 24 May 2026 15:07:18 +0200 Subject: [PATCH] fix(itinerary): suppress false-positive UniqueTogetherValidator in CollectionItineraryItemSerializer (#1157) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DRF 3.15 inspects `UniqueConstraint` entries from `Model._meta.constraints` and auto-generates `UniqueTogetherValidator` objects for them, but strips each constraint's `condition` argument in the process. The `CollectionItineraryItem` model has two conditional constraints: - `unique_order_per_collection_day`: unique `(collection, date, order)` only when `is_global=False AND date IS NOT NULL` - `unique_order_per_collection_global`: unique `(collection, order)` only when `is_global=True` Without their conditions, DRF turns the second constraint into a validator that checks `(collection, order)` across *all* rows regardless of type. This means adding any dated itinerary item (transportation, lodging, etc.) with `order=0` is rejected with 400 whenever a trip-wide (global) item already holds `order=0` for the same collection — which is almost always, since global items start at order 0. Fix: set `validators = []` on the serializer Meta to suppress the incorrectly-stripped validators. The view already adjusts `order` to avoid real conflicts within each group, and the DB-level constraints continue to enforce conditional uniqueness correctly. This actually fixes #1153 for me Co-authored-by: Claude Sonnet 4.6 --- backend/server/adventures/serializers.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/backend/server/adventures/serializers.py b/backend/server/adventures/serializers.py index bc07cee1..93272086 100644 --- a/backend/server/adventures/serializers.py +++ b/backend/server/adventures/serializers.py @@ -1071,6 +1071,11 @@ class CollectionItineraryItemSerializer(CustomModelSerializer): model = CollectionItineraryItem fields = ['id', 'collection', 'content_type', 'object_id', 'item', 'date', 'is_global', 'order', 'start_datetime', 'end_datetime', 'created_at', 'object_name'] read_only_fields = ['id', 'created_at', 'start_datetime', 'end_datetime', 'item', 'object_name'] + # DRF 3.15 generates UniqueTogetherValidator from UniqueConstraints without applying + # their conditions, causing false 400s (e.g. a dated item with order=0 is rejected + # when a global item with the same order exists). The view and DB constraints + # already enforce the correct conditional uniqueness. + validators = [] def validate(self, attrs): data = super().validate(attrs)