openwisp / openwisp/openwisp-controller
[bug] Template.clean() corrections land one write late over the REST API
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 773
- Forks
- 315
- Avg merge
- 2d 16h
- Merged PRs (30d)
- 14
Description
Describe the bug
ValidatedModelSerializer.validate() only applies incoming data when there is no
instance (creation); on PUT/PATCH it runs full_clean() on the instance as
loaded. So Template.clean() never sees the change being saved, and its
type-scoped corrections are applied one write late — the offending write stores
an inconsistent row, and some later unrelated write happens to fix it.
TemplateSerializer.validate_vpn does not catch this: it only fires when both
type and vpn are present in initial_data, so a type-only PATCH bypasses it.
Steps To Reproduce
- Create a template with
type="vpn"and a VPN attached. PATCH /api/v1/controller/template/<pk>/with
{"type": "generic", "config": {"interfaces": []}}→200.- Re-read the row:
typeisgenericbutvpnis still set, contradicting
clean()'s "clears VPN specific fields if type is not VPN". PATCHanything else, e.g.{"name": "renamed"}→ only now isvpnset to
None.
Same shape for required/default: PATCH {"required": true} stores
required=True, default=False, and default becomes True only on a later
write.
Expected behavior
The type change itself should clear vpn/auto_cert, and required should
force default on the same write.
Depends on openwisp/openwisp-utils#760 — and note that if that
lands as copy-based validation, Template.clean() will need to stop correcting
by assignment, since those corrections would no longer be saved at all.
Screenshots
N/A.
System Informatioon:
- OS: Pop!_OS 24.04 LTS
- Python Version: Python 3.13.5
- Django Version: Django 5.2.16
- Browser and Browser Version (if applicable): N/A (REST API)
Also: openwisp-controller 1.2.3, openwisp-utils 1.2.2, djangorestframework
3.16.1.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by tracing ValidatedModelSerializer.validate() and the TemplateSerializer.validate_vpn entry point, then inspect Template.clean() and the PUT/PATCH save path. Reproduce the type-only and required-only PATCH cases described in the issue. Done means each change applies its related corrections in the same write, with tests covering both cases and compatibility with openwisp-utils#760.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- django, python
- Domain
- api, backend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 52/100