diff --git a/djangorota/rota/forms.py b/djangorota/rota/forms.py index 72eb453..129aa92 100644 --- a/djangorota/rota/forms.py +++ b/djangorota/rota/forms.py @@ -168,11 +168,40 @@ class WorkerForm(forms.ModelForm): if val is None or val == "": opts[k] = [] else: - try: - parsed = json.loads(val) - except Exception: + # If the cleaned value is a JSON string, parse it. If + # it's already a Python structure (possibly containing + # pydantic models from `clean()`), keep it but normalize + # any model instances into serializable dicts. + if isinstance(val, str): + try: + parsed = json.loads(val) + except Exception: + parsed = val + else: parsed = val - opts[k] = parsed + + def _normalize(obj): + # Normalize pydantic BaseModel instances (v2:v1) + if hasattr(obj, "model_dump"): + try: + return obj.model_dump() + except Exception: + pass + if hasattr(obj, "dict") and not isinstance(obj, dict): + try: + return obj.dict() + except Exception: + pass + # Recurse lists/tuples + if isinstance(obj, list): + return [_normalize(i) for i in obj] + if isinstance(obj, tuple): + return [_normalize(i) for i in obj] + if isinstance(obj, dict): + return {k: _normalize(v) for k, v in obj.items()} + return obj + + opts[k] = _normalize(parsed) instance.options = opts if commit: