forked from CGM_Public/pretix_original
Bootstrap the form magic for inline restriction formset variation
controls
This commit is contained in:
@@ -213,4 +213,83 @@ In our example, the implementation could look like this::
|
|||||||
If you do not copy down to the ``dict`` objects, you will run into
|
If you do not copy down to the ``dict`` objects, you will run into
|
||||||
interference problems with other plugins.
|
interference problems with other plugins.
|
||||||
|
|
||||||
|
Control interface formsets
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
To make it possible for the event organizer to configure your restriction, there is a
|
||||||
|
'Restrictions' page in the item configuration. This page is able to show a formset for
|
||||||
|
each restriction plugin, but *you* are required to create this formset. This is why you
|
||||||
|
should listen to the the ``tixlcontrol.signals.restriction_formset`` signal.
|
||||||
|
|
||||||
|
Currently, the signal comes with only one keyword argument:
|
||||||
|
|
||||||
|
``item``
|
||||||
|
The instance of ``tixlbase.models.Item`` we want a formset for.
|
||||||
|
|
||||||
|
You are expected to return a dict containing the following items:
|
||||||
|
|
||||||
|
``formsetclass``
|
||||||
|
An inline formset class (not a formset object).
|
||||||
|
|
||||||
|
``prefix``
|
||||||
|
A unique prefix for your queryset.
|
||||||
|
|
||||||
|
``title``
|
||||||
|
A title for your formset (normally your plugin name)
|
||||||
|
|
||||||
|
|
||||||
|
Our time restriction example looks like this::
|
||||||
|
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
from django.dispatch import receiver
|
||||||
|
from django.forms.models import inlineformset_factory
|
||||||
|
|
||||||
|
from tixlcontrol.signals import restriction_formset
|
||||||
|
from tixlbase.models import Item
|
||||||
|
from tixlcontrol.views.forms import (
|
||||||
|
VariationsField, RestrictionInlineFormset, RestrictionForm
|
||||||
|
)
|
||||||
|
|
||||||
|
from .models import TimeRestriction
|
||||||
|
|
||||||
|
class TimeRestrictionForm(RestrictionForm):
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = TimeRestriction
|
||||||
|
localized_fields = '__all__'
|
||||||
|
fields = [
|
||||||
|
'variations',
|
||||||
|
'timeframe_from',
|
||||||
|
'timeframe_to',
|
||||||
|
'price',
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@receiver(restriction_formset)
|
||||||
|
def formset_handler(sender, **kwargs):
|
||||||
|
formset = inlineformset_factory(
|
||||||
|
Item,
|
||||||
|
TimeRestriction,
|
||||||
|
formset=RestrictionInlineFormset,
|
||||||
|
form=TimeRestrictionForm,
|
||||||
|
can_order=False,
|
||||||
|
can_delete=True,
|
||||||
|
extra=0,
|
||||||
|
)
|
||||||
|
|
||||||
|
return {
|
||||||
|
'title': _('Restriction by time'),
|
||||||
|
'formsetclass': formset,
|
||||||
|
'prefix': 'timerestriction',
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.. NOTE::
|
||||||
|
If you do use the ``RestrictionInlineFormset``, ``RestrictionForm`` and
|
||||||
|
``VariationsField`` classes in your implementation, we will do a lot of magic for you
|
||||||
|
to display the ``variations`` field in the form in a nice and consistent way. So please,
|
||||||
|
use these base classes and test carefully, if you make any changes to the behaviour
|
||||||
|
of this field.
|
||||||
|
|
||||||
|
|
||||||
.. _caching feature: https://docs.djangoproject.com/en/1.7/topics/cache/
|
.. _caching feature: https://docs.djangoproject.com/en/1.7/topics/cache/
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
<script type="form-template" data-formset-empty-form>
|
<script type="form-template" data-formset-empty-form>
|
||||||
{% escapescript %}
|
{% escapescript %}
|
||||||
<div class="form-horizontal" data-formset-form>
|
<div class="form-horizontal" data-formset-form>
|
||||||
{% bootstrap_form set.formset.empty_form layout="horizontal" %}
|
{% bootstrap_form set.formset.initialized_empty_form layout="horizontal" %}
|
||||||
</div>
|
</div>
|
||||||
{% endescapescript %}
|
{% endescapescript %}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -30,3 +30,48 @@ class TolerantFormsetModelForm(forms.ModelForm):
|
|||||||
if field._has_changed(initial_value, data_value):
|
if field._has_changed(initial_value, data_value):
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
class RestrictionForm(forms.ModelForm):
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
if 'item' in kwargs:
|
||||||
|
self.item = kwargs['item']
|
||||||
|
del kwargs['item']
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
if 'variations' in self.fields:
|
||||||
|
self.fields['variations'] = VariationsField(item=self.item)
|
||||||
|
|
||||||
|
|
||||||
|
class RestrictionInlineFormset(forms.BaseInlineFormSet):
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
def initialized_empty_form(self):
|
||||||
|
form = self.form(
|
||||||
|
auto_id=self.auto_id,
|
||||||
|
prefix=self.add_prefix('__prefix__'),
|
||||||
|
empty_permitted=True,
|
||||||
|
item=self.instance
|
||||||
|
)
|
||||||
|
return form
|
||||||
|
|
||||||
|
def _construct_form(self, i, **kwargs):
|
||||||
|
kwargs['item'] = self.instance
|
||||||
|
return super()._construct_form(i, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
class VariationsField(forms.ModelMultipleChoiceField):
|
||||||
|
|
||||||
|
def __init__(self, item=None, **kwargs):
|
||||||
|
self.item = item
|
||||||
|
super().__init__(self, **kwargs)
|
||||||
|
|
||||||
|
def _get_choices(self):
|
||||||
|
if not hasattr(self, 'item'):
|
||||||
|
return ()
|
||||||
|
print(self.item.pk)
|
||||||
|
return ()
|
||||||
|
|
||||||
|
choices = property(_get_choices, forms.ChoiceField._set_choices)
|
||||||
|
|||||||
@@ -649,7 +649,7 @@ class ItemRestrictions(ItemDetailMixin, EventPermissionRequiredMixin, TemplateVi
|
|||||||
for receiver, response in responses:
|
for receiver, response in responses:
|
||||||
response['formset'] = response['formsetclass'](
|
response['formset'] = response['formsetclass'](
|
||||||
self.request.POST if self.request.method == 'POST' else None,
|
self.request.POST if self.request.method == 'POST' else None,
|
||||||
queryset=response['queryset'],
|
instance=self.object,
|
||||||
prefix=response['prefix'],
|
prefix=response['prefix'],
|
||||||
)
|
)
|
||||||
formsets.append(response)
|
formsets.append(response)
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
from django.dispatch import receiver
|
from django.dispatch import receiver
|
||||||
from django.utils.timezone import now
|
from django.utils.timezone import now
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from django import forms
|
from django.forms.models import inlineformset_factory
|
||||||
from django.forms.models import modelformset_factory
|
|
||||||
|
|
||||||
from tixlbase.signals import determine_availability
|
from tixlbase.signals import determine_availability
|
||||||
|
from tixlbase.models import Item
|
||||||
|
from tixlcontrol.views.forms import VariationsField, RestrictionInlineFormset, RestrictionForm
|
||||||
from tixlcontrol.signals import restriction_formset
|
from tixlcontrol.signals import restriction_formset
|
||||||
|
|
||||||
from .models import TimeRestriction
|
from .models import TimeRestriction
|
||||||
@@ -111,11 +112,13 @@ def availability_handler(sender, **kwargs):
|
|||||||
return variations
|
return variations
|
||||||
|
|
||||||
|
|
||||||
class TimeRestrictionForm(forms.ModelForm):
|
class TimeRestrictionForm(RestrictionForm):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = TimeRestriction
|
model = TimeRestriction
|
||||||
localized_fields = '__all__'
|
localized_fields = '__all__'
|
||||||
fields = [
|
fields = [
|
||||||
|
'variations',
|
||||||
'timeframe_from',
|
'timeframe_from',
|
||||||
'timeframe_to',
|
'timeframe_to',
|
||||||
'price',
|
'price',
|
||||||
@@ -124,21 +127,18 @@ class TimeRestrictionForm(forms.ModelForm):
|
|||||||
|
|
||||||
@receiver(restriction_formset)
|
@receiver(restriction_formset)
|
||||||
def formset_handler(sender, **kwargs):
|
def formset_handler(sender, **kwargs):
|
||||||
# Handle the signal's input arguments
|
formset = inlineformset_factory(
|
||||||
item = kwargs['item']
|
Item,
|
||||||
|
|
||||||
formset = modelformset_factory(
|
|
||||||
TimeRestriction,
|
TimeRestriction,
|
||||||
|
formset=RestrictionInlineFormset,
|
||||||
form=TimeRestrictionForm,
|
form=TimeRestrictionForm,
|
||||||
can_order=False,
|
can_order=False,
|
||||||
can_delete=True,
|
can_delete=True,
|
||||||
extra=0,
|
extra=0,
|
||||||
)
|
)
|
||||||
queryset = TimeRestriction.objects.filter(item=item)
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'title': _('Restriction by time'),
|
'title': _('Restriction by time'),
|
||||||
'formsetclass': formset,
|
'formsetclass': formset,
|
||||||
'queryset': queryset,
|
|
||||||
'prefix': 'timerestriction',
|
'prefix': 'timerestriction',
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user