Reputation: 4285
i have used django inline formset so make a single crud on two models. Unlike a django form,django formset works with multiple forms at a time.So its really confusing for me to validate django formset.but i need to validate my django formset.I really i hasn't found any solution yet.
I have two models namely Discount and Discount products.I have used django formset for discount products formsets among with discount form.
By default formsets allows user to avoid all the form when creating a new instance or update a new instance,which actually make sense,because there can be 15 or 20 forms.In my system , i am also following the same way.
In my discount formsets, there are two fields namely primary variant
and variants
.
If user don't fill up any field of any forms of the formsets,he can do it and can create or update only discount form object,which is fine.(remember discount form is reside above the discount products formsets).
but if he fill only variant
field and emty the primary variant
field ,then the user should not allow to do this,because in my system ,a variant
can not be created or updated without primary variant
.But in this point i can't validating it.Because its a formsets.I really need idea how to do this type of validation.
here is he Create view where i am combining the discount and discount products.(Providing only the create view, i hope solution will be same for the update view also)
class DiscountCreate(RequestPassingFormViewMixin, WammuCreateView):
model = Discount
template_name = 'dashboard/discount_form.html'
form_class = DiscountForm
def get_form_kwargs(self, *args, **kwargs):
kwargs = super(DiscountCreate, self).get_form_kwargs(*args, **kwargs)
common = get_object_or_404(Common, pk=self.kwargs['common_pk'])
discount = Discount(common=common)
kwargs['instance'] = discount
return kwargs
def get(self, request, *args, **kwargs):
self.object = None
form_class = self.get_form_class()
form = self.get_form(form_class)
DiscountProductInlineFormSet = inlineformset_factory(Discount, DiscountProducts,
form=DiscountProductForm,
can_delete=True, extra=5)
DiscountProductInlineFormSet.form = staticmethod(curry(DiscountProductForm, request=request))
discount_product_formset = DiscountProductInlineFormSet(instance=self.object)
return self.render_to_response(
self.get_context_data(form=form, discount_formset=discount_product_formset))
def post(self, request, *args, **kwargs):
self.object = Discount()
form = self.get_form(self.form_class)
DiscountProductInlineFormSet = inlineformset_factory(Discount, DiscountProducts,
form=DiscountProductForm,
can_delete=True, extra=5)
DiscountProductInlineFormSet.form = staticmethod(curry(DiscountProductForm, request=request))
if form.is_valid():
self.object = form.save(commit=False)
else:
discount_product_formset = DiscountProductInlineFormSet(request.POST,
instance=self.object)
return self.render_to_response(
context=self.get_context_data(form=form, discount_formset=discount_product_formset))
promotion_product_formset = DiscountProductInlineFormSet(request.POST, instance=self.object)
if discount_product_formset.is_valid():
self.object.save()
discount_product_formset.save()
return super(Discountreate, self).form_valid(form)
else:
return self.render_to_response(
context=self.get_context_data(form=form, discount_formset=discount_product_formset))
and this is my forms where both Discount and Disount Products resides,
class DiscountForm(RequestPassingFormMixin, ModelForm):
class Meta:
model = Discount
def __init__(self, *args, **kwargs):
super(PromotionForm, self).__init__(*args, **kwargs)
common = Chain.objects.get(pk=self.request.session.get('chain_pk'))
class DiscountProductForm(autocomplete_light.ModelForm):
class Meta:
model = DiscountProducts
fields = ['code', 'variants', 'primary_variant']
def __init__(self, *args, **kwargs):
self.request = kwargs.pop("request")
super(DiscountProductForm, self).__init__(*args, **kwargs)
common = Chain.objects.get(pk=self.request.session.get('common_pk'))
self.fields['variants'].queryset = Variant.objects.filter(product__common__pk=common.pk)
self.fields['primary_variant'].queryset = Variant.objects.filter(product__common__pk=common.pk)
Upvotes: 2
Views: 3808
Reputation: 1680
Fields in formset are validated if at least one field is not empty, so everything should work as you expect it by default. You can also read about cleaning and validating fields that depend on each other.
Upvotes: 2
Reputation: 1294
Just add arguments min_num=1
and validate_min=True
into inlineformset_factory
Upvotes: 1
Reputation: 7364
This is my solution when I encountered your problem, In your views.py
from django.forms.formsets import formset_factory, BaseFormSet
# Enables field required on formset even without filling up a singlefield
class RequiredFormSet(BaseFormSet):
def __init__(self, *args, **kwargs):
super(RequiredFormSet, self).__init__(*args, **kwargs)
for form in self.forms:
form.empty_permitted = False
def view(request):
formset = formset_factory(CollegeForm, extra=5, formset=RequiredFormSet)
Upvotes: 0