Bootstrap the form magic for inline restriction formset variation

controls
This commit is contained in:
Raphael Michel
2014-10-14 00:45:42 +02:00
parent 0c6326270c
commit 912b0b4211
5 changed files with 135 additions and 11 deletions

View File

@@ -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/

View File

@@ -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>

View File

@@ -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)

View File

@@ -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)

View File

@@ -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',
} }