Наконец нашел способ и снова многому научился.
Да, это возможно, даже довольно легкий способ. Моя форма использует 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 знака после запятой. Поплавки могут иметь странное поведение при округлении.
Если у вас есть какие-либо вопросы, я с удовольствием открою этот код еще!