Gonzalo Dambra
Gonzalo Dambra

Reputation: 980

How to bind form in Django when it has others parameters

I'm trying to perform .is_valid() after a POST request with my form.

form = DrinkForm(request.POST)

Like this, the "problem" is that this form has other parameters.

forms.py:

class DrinkForm(forms.Form):
    def __init__(self, language, account_id, configurations, *args, **kwargs):
        super(DrinkForm, self).__init__(*args, **kwargs)
        translation.activate(language)

With this, I don't know how to make my form bound (and I can't find any guide or example about this case).

When I print my form called in view with its regular parameters it's everything ok, but if I add request.POST I get nothing.

form_ok = DrinkForm('english', request.session['account_id'], configurations)  # OK
form_not_ok = DrinkForm(request.POST)  # Needs parameters
form_how_to = DrinkForm('english', request.session['account_id'], configurations, request.POST)  # How to?

EDIT: added form and view codes

def create_drink(request):
    if request.method == 'POST':
        c = {}
        c.update(csrf(request))
        data = DrinkForm.build_create_data(request.POST)
        try:  # Tries to create the new drink
            account = Account.objects.get(id=request.session['account_id'])
            drinks_conf = DrinksConf.objects.get(account_id=request.session['account_id'])
            form = DrinkForm(get_language(request), request.session['account_id'], drinks_conf, request.POST)
            print(form)  # Nothing is printed!
            if form.is_valid():
                print('valid?')  # Not printed!
                with transaction.atomic():
                    stock = DrinkStock.objects.create(account=account, stock=0)
                    Drink.objects.create(account=account, name=data['name'], cost=data['cost'], stock=stock,
                                         stock_by=data['stock_by'])
                return JsonResponse(DRINK_CREATE_SUCCESS)
            else:
                print('oh no not valid')  # Neither printed!! What the..?
                return JsonResponse(form_error_response(form.errors))
        except:  # Unknown exception
            return JsonResponse(UNKNOWN_EXCEPTION)

forms.py:

class DrinkForm(forms.Form):
    def __init__(self, language, account_id, drinks_conf, *args, **kwargs):
        super(DrinkForm, self).__init__(*args, **kwargs)
        translation.activate(language)
        self.account_id = account_id  # will be used in the future
        self.drinks_conf = drinks_conf
        options = (
            (1, translation.gettext('Units')),
            (3, translation.gettext('Litters'))
        )
        self.fields['name'] = forms.CharField(
            max_length=100,
            required=True,
            label=translation.gettext('Name'),
            widget=forms.TextInput(attrs={'class': 'form-control dynamic_object_submit'})
        )
        self.fields['cost'] = forms.DecimalField(
            max_digits=14,
            decimal_places=2,
            required=True,
            label=translation.gettext('Cost'),
            widget=forms.NumberInput(attrs={'class': 'form-control dynamic_object_submit'})
        )
        self.fields['stock_by'] = forms.ChoiceField(
            required=True,
            label=translation.gettext('Stock/cost by'),
            choices=options,
            widget=forms.Select(attrs={'class': 'form-control dynamic_object_submit'})
        )

    def clean_cost(self):
        if self.drinks_conf.cost_control is True:
            data = self.cleaned_data['cost']
            if data < 0:
                raise forms.ValidationError(translation.gettext("Cost can't be negative"))

    @staticmethod
    def build_create_data(querydict):
        return {
            'name': querydict.get('name', None),
            'cost': querydict.get('cost', None),
            'stock_by': querydict.get('stock_by', None),
        }

Upvotes: 0

Views: 183

Answers (1)

Iain Shelvington
Iain Shelvington

Reputation: 32294

You can use gettext_lazy on your field labels to provide translation at request time. Now you don't need to pass the language into your initialization method and the post data should bind correctly since you are not dynamically adding fields

from django.utils.translation import gettext_lazy as _

class DrinkForm(forms.Form):

    name = forms.CharField(
        max_length=100,
        required=True,
        label=_('Name'),
        widget=forms.TextInput(attrs={'class': 'form-control dynamic_object_submit'})
    )
    cost = forms.DecimalField(
        max_digits=14,
        decimal_places=2,
        required=True,
        label=_('Cost'),
        widget=forms.NumberInput(attrs={'class': 'form-control dynamic_object_submit'})
    )
    stock_by = forms.ChoiceField(
        required=True,
        label=_('Stock/cost by'),
        choices=(
            (1, _('Units')),
            (3, _('Litters'))
        ),
        widget=forms.Select(attrs={'class': 'form-control dynamic_object_submit'})
    )

Upvotes: 1

Related Questions