Есть ли способ создать больше параметров, чем «выбор» в Wagtail Form Builder - PullRequest
2 голосов
/ 24 марта 2019

Я пишу новую веб-страницу, которая также должна работать как платформа для регистрации на определенных мероприятиях.Я хотел бы добавить options['prices'] на стороне options['choices'] в поле множественного выбора.

Теперь есть поле для выбора, где варианты выбора разделены запятой, я хочу, чтобы другой вводил разницу в цене от значения по умолчаниюв зависимости от выбора (плавает, хотя обработка может быть сделана в другом месте) как "1, 2.5, -1, 0".В конце формы он должен считать сумму значения по умолчанию и всех возможных выборов.

Я попытался изменить wagtail.contrib.contrib.forms.FormBuilder.create_multiselect_field, но безуспешно.Есть ли способ добавить такую ​​функциональность, в основном только один дополнительный ввод параметров?

1 Ответ

1 голос
/ 26 марта 2019

Наконец нашел способ и снова многому научился.

Да, это возможно, даже довольно легкий способ. Моя форма использует AbstractEmailForm, и мне пришлось переопределить следующие методы и переменные:

Класс MyForm (AbstractEmailForm):

form_builder = CustomFormBuilder

def get_submission_class(self):
    return CustomFormSubmission

def process_form_submission(self, form):
    #This function processed input data form.cleaned_data dict when user is submitting the form
    #Fields are defined in CustomFormSubmission

    total_price = self.default_price
    form_fields = self.get_form_fields()

    for i in form_fields:
        if i.prices: #if form creator has defined varying prices for choices
            #creates dict {key=choice, value=price} for every form field
            price_dict = dict(zip(
                [x.strip() for x in i.choices.split(',')],
                [Decimal(x.strip()) for x in i.prices.split(',')], #field type is DecimalField, float is not applicable
            ))

            total_price += price_dict[form.cleaned_data[i.label.lower()]]

    return self.get_submission_class().objects.create(
        form_data=json.dumps(form.cleaned_data, cls=DjangoJSONEncoder),
        page=self,
        price=total_price,
    )

def get_data_fields(self):
    """
    Returns a list of tuples with (field_name, field_label).
    """

    data_fields = [
        ('submit_time', _('Submission date')),
        ('price', _('Total Price')),
    ]
    data_fields += [
        (field.clean_name, field.label)
        for field in self.get_form_fields()
    ]

    return data_fields

Также мне пришлось создать цены для выбора в качестве поля для редактора форм. Это стало возможным благодаря переопределению класса AbstractFormField. Вы должны переопределить каждую функцию create__field () там, где вы хотите применить опцию цен. Ex. поле create_radio_ ниже:

класс FormField (AbstractFormField):

prices = models.TextField(
    verbose_name=_('prices'),
    blank=True,
    help_text=_('Comma separated list of price changes.')
)

panels = [
    FieldPanel('label'),
    FieldPanel('help_text'),
    FieldPanel('required'),
    FieldPanel('field_type', classname="formbuilder-type"),
    FieldPanel('choices', classname="formbuilder-choices"),
    FieldPanel('prices'),
    FieldPanel('default_value', classname="formbuilder-default"),
]

def create_radio_field(self, field, options):
    options['choices'] = [(x.strip(), x.strip()) for x in field.choices.split(',')]
    options['prices'] = [x.strip() for x in field.prices.split(',')]
    return django.forms.ChoiceField(
        widget=django.forms.RadioSelect, 
        **options
    )
enter code here
#remember to create CustomFormBuilder(FormBuilder) if you have custom fields, ex. Generic IP-address:

class CustomFormBuilder(FormBuilder):
    def create_ipaddress_field(self, field, options):
        return forms.GenericIPAddressField(
            **options
    )

Чтобы сохранить это значение, определите поле, которое будет создано в базе данных с помощью CustomFormSubmission (AbstractFormSubmission)

price = models.DecimalField(
    max_digits=16,
    decimal_places=2,
    default=0,
)

def get_data(self):
    """
    Returns dict with form data.
    """
    form_data = json.loads(self.form_data)
    form_data.update({
        'submit_time': self.submit_time,
        'price': self.price,
    })

    return form_data

Валюта сохраняется в моделях django. DecimalField, так как для нее требуется только 2 знака после запятой. Поплавки могут иметь странное поведение при округлении.

Если у вас есть какие-либо вопросы, я с удовольствием открою этот код еще!

...