filter unknown keys from choices due to django-formsets

This commit is contained in:
Richard Schreiber
2026-09-18 13:40:13 +02:00
parent cde6c301b2
commit 08f66fae3a
2 changed files with 58 additions and 21 deletions
+37 -17
View File
@@ -643,7 +643,40 @@ class OrganizerSettingsSerializer(SettingsSerializer):
return 'pub/' + fname
class KeyLabelObjectListField(serializers.Field):
def to_representation(self, value):
# django added unneccessary keys DELETE, ORDER through formsets, filter them here for backwards compat
def strip_unknown_keys(v):
return {k: v[k] for k in v.keys() if k in ("key", "label")}
return [strip_unknown_keys(v) for v in value]
def to_internal_value(self, data):
if data is None:
return data
if not isinstance(data, list):
raise ValidationError("Choices need to be a list or null.")
if not data:
# empty list
return None
if any([not isinstance(choice, dict) for choice in data]):
raise ValidationError("Choices need to contain only objects.")
required_keys = {"key"}
allowed_keys = {"key", "label"}
if not all([required_keys <= set(choice.keys()) <= allowed_keys for choice in data]):
raise ValidationError("Each choice must contain a key and optionally a label.")
choice_keys = [choice.get("key") for choice in data]
if len(set(choice_keys)) < len(choice_keys):
raise ValidationError("Each choice must have a unique key.")
return data
class EventMetaPropertiesSerializer(I18nAwareModelSerializer):
choices = KeyLabelObjectListField(allow_null=True)
class Meta:
model = EventMetaProperty
fields = (
@@ -657,26 +690,13 @@ class EventMetaPropertiesSerializer(I18nAwareModelSerializer):
full_data.update(data)
choices = full_data.get("choices")
if "choices" in data and data["choices"] is not None:
if not isinstance(choices, list):
raise ValidationError("Choices need to be a list or null.")
if any([not isinstance(c, dict) for c in choices]):
raise ValidationError("Choices need to contain only objects.")
required_keys = {"key"}
allowed_keys = {"key", "label"}
if not all([required_keys <= set(c.keys()) <= allowed_keys for c in choices]):
raise ValidationError("Each choice must contain a key and optionally a label.")
if choices:
default = full_data.get("default")
if choices and default:
choice_keys = [c.get("key") for c in choices]
if len(set(choice_keys)) < len(choice_keys):
raise ValidationError("Each choice must have a unique key.")
default = full_data.get("default")
if default and default not in choice_keys:
if default not in choice_keys:
raise ValidationError("You cannot set a default value that is not a valid value.")
if not choices and "choices" in data:
# normalize empty dict to None
# normalize empty dict to None
data["choices"] = None
return data
+21 -4
View File
@@ -29,7 +29,14 @@ def event_meta_property(organizer):
name="Color",
default="Red",
required=False,
choices=None,
choices=[
{
"key": "Red",
"label": "Rot",
"DELETE": False,
"ORDER": 1,
}
],
)
@@ -37,7 +44,7 @@ TEST_TYPE_RES = {
"name": "Color",
"default": "Red",
"required": False,
"choices": None,
"choices": [{"key": "Red", "label": "Rot"}],
'filter_allowed': True,
'filter_public': False,
'protected': False,
@@ -141,6 +148,18 @@ def test_meta_property_patch(token_client, organizer, event_meta_property):
}
)
assert resp.status_code == 400
resp = token_client.patch(
'/api/v1/organizers/{}/event_meta_properties/{}/'
.format(organizer.slug, event_meta_property.pk),
format='json',
data={
"choices": [],
}
)
assert resp.status_code == 200
event_meta_property.refresh_from_db()
assert event_meta_property.choices is None
resp = token_client.patch(
'/api/v1/organizers/{}/event_meta_properties/{}/'
.format(organizer.slug, event_meta_property.pk),
@@ -156,8 +175,6 @@ def test_meta_property_patch(token_client, organizer, event_meta_property):
assert event_meta_property.choices is None
@pytest.mark.django_db
def test_meta_property_delete(token_client, organizer, event_meta_property):
resp = token_client.delete(