improve surverys

This commit is contained in:
Ross
2026-06-29 09:35:12 +01:00
parent 79ba4db4bf
commit c34dcdfd5e
26 changed files with 911 additions and 39 deletions
+121 -1
View File
@@ -1,3 +1,4 @@
import datetime
from django import forms
from django.forms import ModelMultipleChoiceField
from django.contrib.auth.models import User
@@ -14,9 +15,30 @@ class SurveyForm(forms.ModelForm):
class Meta:
model = Survey
fields = ["name", "description", "active", "anonymous", "authors_only", "author"]
fields = [
"name",
"description",
"before_text",
"after_text",
"active",
"anonymous",
"authors_only",
"author"
]
widgets = {
"description": forms.Textarea(attrs={"rows": 3}),
"before_text": forms.Textarea(attrs={"rows": 3, "placeholder": "Instructions shown before the survey starts..."}),
"after_text": forms.Textarea(attrs={"rows": 3, "placeholder": "Thank you message shown after submission..."}),
}
class SurveyQuestionForm(forms.ModelForm):
# Form-only fields for validation rules
min_value = forms.IntegerField(required=False, label="Minimum Value (Integer)")
max_value = forms.IntegerField(required=False, label="Maximum Value (Integer)")
min_date = forms.DateField(required=False, widget=forms.DateInput(attrs={"type": "date"}), label="Minimum Date")
max_date = forms.DateField(required=False, widget=forms.DateInput(attrs={"type": "date"}), label="Maximum Date")
class Meta:
model = SurveyQuestion
fields = ["text", "question_type", "choices", "required", "position"]
@@ -24,6 +46,52 @@ class SurveyQuestionForm(forms.ModelForm):
"choices": forms.Textarea(attrs={"rows": 4, "placeholder": "Enter each choice on a new line"}),
}
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Populate initial values for validation fields from validation_rules dict
if self.instance and self.instance.pk and self.instance.validation_rules:
rules = self.instance.validation_rules
self.fields["min_value"].initial = rules.get("min_value")
self.fields["max_value"].initial = rules.get("max_value")
min_date_val = rules.get("min_date")
if min_date_val:
try:
self.fields["min_date"].initial = datetime.date.fromisoformat(min_date_val)
except ValueError:
pass
max_date_val = rules.get("max_date")
if max_date_val:
try:
self.fields["max_date"].initial = datetime.date.fromisoformat(max_date_val)
except ValueError:
pass
def save(self, commit=True):
instance = super().save(commit=False)
# Build validation_rules dict
rules = {}
min_val = self.cleaned_data.get("min_value")
max_val = self.cleaned_data.get("max_value")
min_dt = self.cleaned_data.get("min_date")
max_dt = self.cleaned_data.get("max_date")
if min_val is not None:
rules["min_value"] = min_val
if max_val is not None:
rules["max_value"] = max_val
if min_dt is not None:
rules["min_date"] = min_dt.isoformat()
if max_dt is not None:
rules["max_date"] = max_dt.isoformat()
instance.validation_rules = rules
if commit:
instance.save()
return instance
class SurveyTakeForm(forms.Form):
def __init__(self, *args, **kwargs):
self.survey = kwargs.pop("survey")
@@ -53,6 +121,54 @@ class SurveyTakeForm(forms.Form):
choices=[(str(i), str(i)) for i in range(1, 6)],
widget=forms.RadioSelect(attrs={"class": "form-check-input"}),
)
elif q.question_type == SurveyQuestion.QuestionType.INTEGER:
rules = q.validation_rules or {}
self.fields[field_name] = forms.IntegerField(
label=q.text,
required=q.required,
min_value=rules.get("min_value"),
max_value=rules.get("max_value"),
widget=forms.NumberInput(attrs={"class": "form-control"})
)
elif q.question_type == SurveyQuestion.QuestionType.DATE:
rules = q.validation_rules or {}
attrs = {"type": "date", "class": "form-control"}
if rules.get("min_date"):
attrs["min"] = rules["min_date"]
if rules.get("max_date"):
attrs["max"] = rules["max_date"]
self.fields[field_name] = forms.DateField(
label=q.text,
required=q.required,
widget=forms.DateInput(attrs=attrs)
)
def clean(self):
cleaned_data = super().clean()
for q in self.questions:
field_name = f"question_{q.pk}"
val = cleaned_data.get(field_name)
if val is not None and val != "":
rules = q.validation_rules or {}
if q.question_type == SurveyQuestion.QuestionType.INTEGER:
min_val = rules.get("min_value")
max_val = rules.get("max_value")
if min_val is not None and val < min_val:
self.add_error(field_name, f"Value must be at least {min_val}.")
if max_val is not None and val > max_val:
self.add_error(field_name, f"Value cannot exceed {max_val}.")
elif q.question_type == SurveyQuestion.QuestionType.DATE:
min_dt_str = rules.get("min_date")
max_dt_str = rules.get("max_date")
if min_dt_str:
min_dt = datetime.date.fromisoformat(min_dt_str)
if val < min_dt:
self.add_error(field_name, f"Date cannot be before {min_dt_str}.")
if max_dt_str:
max_dt = datetime.date.fromisoformat(max_dt_str)
if val > max_dt:
self.add_error(field_name, f"Date cannot be after {max_dt_str}.")
return cleaned_data
def save(self, user=None, cid=None, content_type=None, object_id=None, pre_or_post='GENERAL'):
response_user = None if self.survey.anonymous else user
@@ -78,5 +194,9 @@ class SurveyTakeForm(forms.Form):
ans.choice_answer = val
elif q.question_type == SurveyQuestion.QuestionType.RATING:
ans.rating_answer = int(val)
elif q.question_type == SurveyQuestion.QuestionType.INTEGER:
ans.integer_answer = int(val)
elif q.question_type == SurveyQuestion.QuestionType.DATE:
ans.date_answer = val
ans.save()
return response