mirror of
https://github.com/pretix/pretix.git
synced 2025-12-05 21:32:28 +00:00
somewhat presentable MultiValueField without validation
This commit is contained in:
@@ -34,6 +34,7 @@
|
||||
# License for the specific language governing permissions and limitations under the License.
|
||||
import copy
|
||||
import os
|
||||
from collections import namedtuple
|
||||
from decimal import Decimal
|
||||
from urllib.parse import urlencode
|
||||
|
||||
@@ -60,7 +61,7 @@ from pretix.base.forms import I18nFormSet, I18nMarkdownTextarea, I18nModelForm
|
||||
from pretix.base.forms.widgets import DatePickerWidget
|
||||
from pretix.base.models import (
|
||||
Item, ItemCategory, ItemProgramTime, ItemVariation, Order, OrderPosition,
|
||||
Question, QuestionOption, Quota, SubEvent,
|
||||
Question, QuestionOption, Quota, SubEvent, Event
|
||||
)
|
||||
from pretix.base.models.items import ItemAddOn, ItemBundle, ItemMetaValue
|
||||
from pretix.base.signals import item_copy_data
|
||||
@@ -274,6 +275,85 @@ class QuestionOptionForm(I18nModelForm):
|
||||
'answer',
|
||||
]
|
||||
|
||||
subeventSelectionParts = namedtuple('subeventWidgetParts', ['selection', 'startDateTime', 'endDateTime', 'subevents'])
|
||||
|
||||
class SubeventSelectionWidget(forms.MultiWidget):
|
||||
template_name = 'pretixcontrol/forms/widgets/subeventselection.html'
|
||||
parts = subeventSelectionParts
|
||||
|
||||
def __init__(self, event: Event, status_choices, subevent_choices, *args, **kwargs):
|
||||
widgets = subeventSelectionParts(
|
||||
selection=forms.RadioSelect(
|
||||
choices=status_choices,
|
||||
),
|
||||
startDateTime=SplitDateTimePickerWidget(),
|
||||
endDateTime=SplitDateTimePickerWidget(),
|
||||
subevents=Select2(
|
||||
attrs={
|
||||
'class': 'simple-subevent-choice',
|
||||
'data-model-select2': 'event',
|
||||
'data-select2-url': reverse('control:event.subevents.select2', kwargs={
|
||||
'event': event.slug,
|
||||
'organizer': event.organizer.slug,
|
||||
}),
|
||||
'data-placeholder': pgettext_lazy('subevent', 'All dates')
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
widgets.subevents.choices = subevent_choices
|
||||
super().__init__(widgets=widgets, *args, **kwargs)
|
||||
|
||||
def decompress(self, value):
|
||||
if value:
|
||||
return value
|
||||
return ['subevent', "", ""]
|
||||
|
||||
|
||||
|
||||
class SubeventSelectionField(forms.MultiValueField):
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.event = kwargs.pop('event')
|
||||
|
||||
choices = [
|
||||
("subevent", _("Subevent")),
|
||||
("timerange", _("Timerange"))
|
||||
]
|
||||
|
||||
fields = subeventSelectionParts(
|
||||
selection=forms.ChoiceField(
|
||||
choices=choices,
|
||||
required=True,
|
||||
initial="subevent",
|
||||
),
|
||||
startDateTime=SplitDateTimeField(
|
||||
required=False,
|
||||
),
|
||||
endDateTime=SplitDateTimeField(
|
||||
required=False,
|
||||
),
|
||||
subevents=forms.ModelChoiceField(
|
||||
required=False,
|
||||
queryset=self.event.subevents,
|
||||
empty_label = pgettext_lazy('subevent', 'All dates')
|
||||
)
|
||||
)
|
||||
|
||||
kwargs['widget'] = SubeventSelectionWidget(
|
||||
event=self.event,
|
||||
status_choices=choices,
|
||||
subevent_choices=fields.subevents.widget.choices,
|
||||
)
|
||||
|
||||
super().__init__(
|
||||
fields=fields, require_all_fields=False, *args, **kwargs
|
||||
)
|
||||
|
||||
def compress(self, data_list):
|
||||
if not data_list:
|
||||
return None
|
||||
return subeventSelectionParts(*data_list)
|
||||
|
||||
|
||||
class QuestionFilterForm(forms.Form):
|
||||
STATUS_VARIANTS = [
|
||||
@@ -296,42 +376,36 @@ class QuestionFilterForm(forms.Form):
|
||||
}
|
||||
),
|
||||
required=False,
|
||||
label=_("Status"),
|
||||
)
|
||||
item = forms.ChoiceField(
|
||||
choices=[],
|
||||
widget=forms.Select(
|
||||
attrs={'class': 'form-control'}
|
||||
),
|
||||
required=False
|
||||
)
|
||||
subevent = forms.ModelChoiceField(
|
||||
queryset=SubEvent.objects.none(),
|
||||
required=False,
|
||||
empty_label=pgettext_lazy('subevent', 'All dates')
|
||||
label=_("Items")
|
||||
)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.event = kwargs.pop('event')
|
||||
super().__init__(*args, **kwargs)
|
||||
self.initial['status'] = "np"
|
||||
self.fields['item'].choices = [('', _('All products'))] + [(item.id, item.name) for item in Item.objects.filter(event=self.event)]
|
||||
|
||||
if self.event.has_subevents:
|
||||
self.fields["subevent"].queryset = self.event.subevents.all()
|
||||
self.fields['subevent'].widget = Select2(
|
||||
attrs={
|
||||
'class': 'form-control simple-subevent-choice',
|
||||
'data-model-select2': 'event',
|
||||
'data-select2-url': reverse('control:event.subevents.select2', kwargs={
|
||||
'event': self.event.slug,
|
||||
'organizer': self.event.organizer.slug,
|
||||
}),
|
||||
'data-placeholder': pgettext_lazy('subevent', 'All dates')
|
||||
}
|
||||
self.fields['subevent_selection'] = SubeventSelectionField(
|
||||
event=self.event,
|
||||
label=_("Subevents"),
|
||||
help_text=_(" Select the subevents that should be included in the statistics either by subevent or by the timerange in which they occur.")
|
||||
)
|
||||
self.fields['subevent'].widget.choices = self.fields['subevent'].choices
|
||||
else:
|
||||
del self.fields['subevent']
|
||||
|
||||
self.initial['status'] = "np"
|
||||
self.fields['item'].choices = [('', _('All products'))] + [(item.id, item.name) for item in
|
||||
Item.objects.filter(event=self.event)]
|
||||
|
||||
def clean(self):
|
||||
super().clean()
|
||||
import pprint
|
||||
pprint.pprint(self.cleaned_data)
|
||||
|
||||
def order_position_queryset(self):
|
||||
fdata = self.data
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
{% load i18n %}
|
||||
<div class="subevent-selection col-lg-12">
|
||||
{% for group_name, group_choices, group-index in widget.subwidgets.0.optgroups %}
|
||||
{% for selopt in group_choices %}
|
||||
<div class="radio">
|
||||
<label class="col-lg-2">
|
||||
<input type="radio" name="{{ widget.subwidgets.0.name }}" value="{{ selopt.value }}"
|
||||
{% include "django/forms/widgets/attrs.html" with widget=selopt %} />
|
||||
{{ selopt.label }}
|
||||
</label>
|
||||
|
||||
{% if selopt.value == "subevent" %}
|
||||
|
||||
{% with widget.subwidgets.3 as widget %}
|
||||
{% include widget.template_name %}
|
||||
{% endwith %}
|
||||
|
||||
{% elif selopt.value == "timerange" %}
|
||||
|
||||
{% with widget.subwidgets.1 as widget %}
|
||||
{% include widget.template_name %}
|
||||
{% endwith %}
|
||||
|
||||
<span class="spacer">{% trans "until" %}</span>
|
||||
|
||||
{% with widget.subwidgets.2 as widget %}
|
||||
{% include widget.template_name %}
|
||||
{% endwith %}
|
||||
|
||||
|
||||
{% endif %}
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
@@ -5,6 +5,11 @@
|
||||
{% load formset_tags %}
|
||||
{% block title %}{% blocktrans with name=question.question %}Question: {{ name }}{% endblocktrans %}{% endblock %}
|
||||
{% block inside %}
|
||||
{% for e in form.errors %}
|
||||
<div class="alert alert-danger has-error">
|
||||
{{ e }}
|
||||
</div>
|
||||
{% endfor %}
|
||||
<h1>
|
||||
{% blocktrans with name=question.question %}Question: {{ name }}{% endblocktrans %}
|
||||
<a href="{% url "control:event.items.questions.edit" event=request.event.slug organizer=request.event.organizer.slug question=question.pk %}"
|
||||
@@ -20,17 +25,24 @@
|
||||
</div>
|
||||
<form class="panel-body filter-form" action="" method="get">
|
||||
<div class="row">
|
||||
<div class="col-lg-2 col-sm-6 col-xs-6">
|
||||
{{ form.status }}
|
||||
|
||||
<div class="col-lg-4 col-sm-6 col-xs-6">
|
||||
{% bootstrap_label form.status.label %}
|
||||
{% bootstrap_field form.status layout="inline" %}
|
||||
|
||||
</div>
|
||||
<div class="col-lg-5 col-sm-6 col-xs-6">
|
||||
{{ form.item }}
|
||||
<div class="col-lg-8 col-sm-6 col-xs-6">
|
||||
{% bootstrap_label form.item.label %}
|
||||
{% bootstrap_field form.item layout="inline" %}
|
||||
</div>
|
||||
|
||||
<div class="col-lg-12 col-sm-6 col-xs-6">
|
||||
{% bootstrap_label form.subevent_selection.label %}
|
||||
{{ form.subevent_selection }}
|
||||
<div class="help-block">
|
||||
{{ form.subevent_selection.help_text }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-5 col-sm-6 col-xs-6">
|
||||
<p>
|
||||
{{ form.subevent }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-right">
|
||||
<button class="btn btn-primary btn-lg" type="submit">
|
||||
|
||||
@@ -777,7 +777,10 @@ class QuestionView(EventPermissionRequiredMixin, ChartContainingView, DetailView
|
||||
def get_context_data(self, **kwargs):
|
||||
ctx = super().get_context_data()
|
||||
ctx['items'] = self.object.items.all()
|
||||
ctx['form'] = QuestionFilterForm(data=self.request.GET, event=self.request.event)
|
||||
ctx['form'] = QuestionFilterForm(
|
||||
data=self.request.GET,
|
||||
event=self.request.event
|
||||
)
|
||||
if ctx['form'].is_valid():
|
||||
opqs = ctx['form'].order_position_queryset()
|
||||
stats = self.get_answer_statistics(opqs)
|
||||
|
||||
@@ -216,6 +216,20 @@ td > .form-group > .checkbox {
|
||||
.input-group-btn .btn {
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
.subevent-selection{
|
||||
.splitdatetimerow{
|
||||
max-width: 500px;
|
||||
display: inline-block;
|
||||
}
|
||||
.spacer{
|
||||
margin-left: 20px;
|
||||
margin-right: 20px;
|
||||
}
|
||||
.select2{
|
||||
max-width:500px;
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
.reldatetime {
|
||||
input[type=text], select {
|
||||
display: inline-block;
|
||||
|
||||
Reference in New Issue
Block a user