Generic form system: generic_forms app foundation (PR 1/5) - #4705
Open
marcoacierno wants to merge 10 commits into
Open
Generic form system: generic_forms app foundation (PR 1/5)#4705marcoacierno wants to merge 10 commits into
marcoacierno wants to merge 10 commits into
Conversation
Foundation for the generic form system: conference-scoped forms with admin-authorable questions and JSON answers (versioned envelope). DB constraints: one answer per (form, user); at most one form per (conference, purpose) except for generic-purpose forms.
question_type, options, required and the parent form become immutable (and deletion is blocked) as soon as any FormAnswer exists, so stored answers always match their questions. Label, description, order and active stay editable; deactivation replaces deletion.
validate_answers checks a flat {question_id: value} map against a
form's active questions: required, per-type value shape, option
membership (every multi-select item), URL format and max length.
wrap_answers/unwrap_answers implement the {version: 1, answers: {...}}
storage envelope with version dispatch.
FormAdmin with inline questions (freeze rule surfaces via model validation so new questions can still be added to answered forms; inline deletion is blocked once answers exist). FormAnswerAdmin is read-only.
- validate_answers: reject non-dict answers and non-string multi-select
items with errors instead of crashing (client-controlled JSON input)
- validate options shape at authoring time (list of unique {id, label}
string pairs, required for select types, forbidden otherwise) so a
malformed options blob can't 500 every submission
- unwrap_answers: ValueError on malformed envelopes, empty dict allowed
- block FormAnswer deletion in admin (deleting answers would unfreeze
questions and silently destroy submissions)
- freeze Form.conference/purpose once answered (model + admin readonly)
- question delete guard moved to pre_delete signal so queryset deletes
are covered; explicit-pk saves no longer crash (_state.adding)
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Contributor
|
Adds the Correctness
Minor
|
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #4705 +/- ##
==========================================
+ Coverage 92.43% 92.45% +0.01%
==========================================
Files 355 358 +3
Lines 10719 10888 +169
Branches 818 852 +34
==========================================
+ Hits 9908 10066 +158
- Misses 698 706 +8
- Partials 113 116 +3 🚀 New features to boost your workflow:
|
Replace substring checks (e.g. asserting "5" appears somewhere in the error) with exact error-dict equality and distinctive pytest.raises match phrases, so tests assert the actual behavior and catch stray extra errors.
- validate_answers: plain dict instead of defaultdict + trailing filter comprehension (empty entries no longer created then dropped) - extract _is_valid_option predicate from the option-shape mega-boolean - reuse a module-level URLValidator; drop redundant map(str, ...) on already-validated strings; idiomatic empty-dict check in unwrap - FormAnswer admin: select related form__conference/user (Form.__str__ renders the conference name)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
First PR of the generic form system stack (spec:
specs/generic-form-system.md, plan:tasks/generic-forms/plan.md). Adds thegeneric_formsDjango app — no consumers wired yet; grants integration, GraphQL and frontend come in the next PRs of the stack.Form(conference + purpose, one per (conference, purpose) exceptgeneric),FormQuestion(6 types: text/textarea/select/multi_select/boolean/url; options as[{id, label}]JSON; validated at authoring),FormAnswer(one per (form, user), versioned JSON envelope{"version": 1, "answers": {...}})type/options/required/formand formconference/purposebecome immutable; question deletion blocked (pre_delete signal, covers queryset deletes). Labels/description/order/active stay editable; deactivate replaces deletevalidate_answersservice: single source of truth for answer validation (required, per-type shape, option membership, URL, max length); never crashes on malformed client JSONFormAnswerfully read-only (add/change/delete blocked — deleting answers would unfreeze questions and destroy submissions)Test plan
generic_forms/tests/): constraints, freeze rules incl. queryset-delete bypass, validation accept/reject per question type, envelope round-trip, admin permissionsStack: PR1 (this) → PR2 GraphQL query → PR3 grants backend → PR4 admin display/export → PR5 frontend.