Jeroj82
Jeroj82

Reputation: 401

django - clean dynamic field

I have a model:

class Order(models.Model):
    order_type = models.ForeignKey(OrderType)
    quantity = models.IntegerField(max_digits=10, decimal_places=4)
    product = models.ForeignKey(Product)

I added the form filed dynamically:

class OrderForm(ModelForm):
    class Meta:
        model = Order
        fields = [
            'order_type', 'product'
        ]
        widgets = {
            'order_type': Select(attrs={'class': 'form-control'}),
            'product': Select(attrs={'class': 'form-control'}),
        }

    def __init__(self, types=[],*args, **kwargs):
        super(OrderForm, self).__init__(*args, **kwargs)

        if "AMOUNT" in types:
            self.fields['quantity'] = IntegerField(
                NumberInput(attrs={'class': 'form-control'})
            )

And in CreateView I overwrite post. In the frontend I'm sending ajax with data or not (if data is sent, I want to generate form with addition quantity field), then I replace the old form with this new:

class OrderCreateView(CreateView):
    model = Order
    form_class = OrderForm

    def post(self, request, *args, **kwargs):
        self.object = None
        d = request.POST.get('DATA', None)
        if d is not None:

            form = self.form_class(
                types=["AMOUNT"],
                **self.kwargs
            )
            return render(
                request, 'form.html', {'form': form}
            )
        else:
            form = self.form_class(**self.kwargs)
            return render(
                request, 'form.html', {'form': form}
            )
        return super(OrderCreateView, self).post(request, *args, **kwargs)

And it "works". I get new form with a quantity. But when I'm trying do submit this form, I get an error

null value in column "quantity" violates not-null constraint

Upvotes: 0

Views: 387

Answers (2)

neverwalkaloner
neverwalkaloner

Reputation: 47364

Last line of your post method is unreachable. Post function will never go here:

return super(OrderCreateView, self).post(request, *args, **kwargs)

I suppose you need to change logic of your code. For example if it possible instead of sending 'DATA' with POST try to send it with GET. Or create another view to render form with 'AMOUNT' field.

UPDATE

Also please note that super().post() calls get_form() which return default instance of form_class. Considering this super().post() probably is not what you really need. Try to perform form validation and form saving manually:

form = self.form_class(
        types=["AMOUNT"],
        **self.kwargs
    )
if form.is_valid():
    instance = self.form.save()
    return super().get()

Upvotes: 1

renno
renno

Reputation: 2827

In your model try to change

quantity = models.IntegerField(max_digits=10, decimal_places=4)

to

quantity = models.IntegerField(max_digits=10, decimal_places=4, null=True, blank=True)

Whenever you don't have the flag "AMOUNT" it tries to create an Order without filling that field.

UPDATE: Try this in your form

fields = [
        'order_type', 'product', 'quantity'
    ]
widgets = {
        'order_type': Select(attrs={'class': 'form-control'}),
        'product': Select(attrs={'class': 'form-control'}),
        'quantity': NumberInput(attrs={'class': 'form-control'}),
    }
def __init__(self, types=[],*args, **kwargs):
    super(OrderForm, self).__init__(*args, **kwargs)

    if "AMOUNT" not in types:
        del self.fields['quantity']

In your view put the super() before as @neverwalkaloner mentioned

Upvotes: 1

Related Questions