From 3ef35df4218a47563d2669f229031699c266940b Mon Sep 17 00:00:00 2001 From: Mira Weller Date: Thu, 17 Sep 2026 16:14:42 +0200 Subject: [PATCH] Add (somewhat hacky) support for text blocks in QuestionsForms --- src/pretix/api/serializers/item.py | 9 ++++++++- src/pretix/base/forms/questions.py | 16 ++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/pretix/api/serializers/item.py b/src/pretix/api/serializers/item.py index 9658d13389..ae0ade3795 100644 --- a/src/pretix/api/serializers/item.py +++ b/src/pretix/api/serializers/item.py @@ -54,6 +54,7 @@ from pretix.base.models import ( SalesChannel, ) from pretix.base.models.items import Questionnaire, QuestionnaireChild +from pretix.base.templatetags.rich_text import rich_text class InlineItemVariationSerializer(SalesChannelMigrationMixin, I18nAwareModelSerializer): @@ -651,13 +652,19 @@ class QuestionRefField(serializers.PrimaryKeyRelatedField): return self.source == '*' +class RenderedMarkdownField(serializers.CharField): + def to_representation(self, value): + return rich_text(value) + + class InlineQuestionnaireChildSerializer(I18nAwareModelSerializer): question = QuestionRefField(source='*', queryset=Question.objects.none()) dependency_question = QuestionRefField(allow_null=True, required=False, queryset=Question.objects.none()) + rendered_help_text = RenderedMarkdownField(read_only=True, source='help_text') class Meta: model = QuestionnaireChild - fields = ('question', 'required', 'label', 'help_text', 'dependency_question', 'dependency_values') + fields = ('question', 'required', 'label', 'help_text', 'dependency_question', 'dependency_values', 'rendered_help_text') def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) diff --git a/src/pretix/base/forms/questions.py b/src/pretix/base/forms/questions.py index 9c5b2ac307..fbb56110c3 100644 --- a/src/pretix/base/forms/questions.py +++ b/src/pretix/base/forms/questions.py @@ -50,6 +50,7 @@ from django.core.exceptions import ValidationError from django.core.files.uploadedfile import SimpleUploadedFile from django.core.validators import MaxValueValidator, MinValueValidator from django.db.models import QuerySet +from django.db import ProgrammingError from django.forms import Select, widgets from django.forms.widgets import FILE_INPUT_CONTRADICTION from django.utils.formats import date_format @@ -865,6 +866,8 @@ class BaseQuestionsForm(forms.Form): initial=initial, widget=WrappedPhoneNumberPrefixWidget() ) + else: + raise ProgrammingError('Invalid question type') field.datafield = datafield if answers: # Cache the answer object for later use @@ -880,6 +883,15 @@ class BaseQuestionsForm(forms.Form): return field + def build_text_block(self, request, event, qc): + return forms.CharField( # TODO(questionnaires): use a less hacky way to format this field + required=False, + label="", + help_text=rich_text((f"#### {qc.label}\n" if qc.label else "") + str(qc.help_text)), + disabled=True, + widget=QuestionCheckboxSelectMultiple, + ) + def check_user_questions(self, d): question_cache = {f.question.pk: f.question for f in self.fields.values() if getattr(f, 'question', None)} @@ -986,6 +998,7 @@ class TicketLevelQuestionsForm(BaseQuestionsForm): if cartpos and item.validity_mode == Item.VALIDITY_MODE_DYNAMIC and item.validity_dynamic_start_choice: self.fields['requested_valid_from'] = self.build_requested_valid_from_field(event, pos, item) + idx = 0 for questionnaire in questionnaires: for child in getattr(questionnaire, 'childlist', questionnaire.children.all()): if child.user_datafield: @@ -993,6 +1006,9 @@ class TicketLevelQuestionsForm(BaseQuestionsForm): self.fields['question_%s' % df.id] = self.build_user_question_field(request, event, pos.answerlist, child, df) elif child.system_datafield: self.fields[child.system_datafield] = self.build_system_question_field(request, event, pos, child) + else: + self.fields['text_%d' % idx] = self.build_text_block(request, event, child) + idx += 1 responses = question_form_fields.send(sender=event, position=pos) data = pos.meta_info_data