Problem: I have a problem with third form that has nested form at first it renders properly when I delete any child form that nested from all the form gets deleted. how can I fix that
End Goal: I wanted to built signup form that consists of three forms first form is basic login info, second form can have multiple instances of the single form where the user can add more form or remove it. and third form if nested from where the user also can add from or remove it. all these in under a single submit button.
What I have done: At this point i'm able to build all of the forms and stored first two forms that are basic signup info and second form that have multiple instances.
# model.py
class Vendor(BaseModel):
user = models.OneToOneField(User, on_delete=models.CASCADE, unique=True)
address = models.CharField(max_length=100)
mobile_no = models.CharField(max_length=12)
gst = models.CharField(max_length=20)
code = models.CharField(max_length=20)
def __str__(self):
if (self.user.first_name != None):
return self.user.username
else:
return self.user.first_name
# Material/s that vendor can process
class VendorMaterial(BaseModel):
vendor = models.ForeignKey(Vendor, on_delete=models.CASCADE)
material = models.ForeignKey(Material, on_delete=models.CASCADE)
class VendorProcess(BaseModel):
vendor = models.ForeignKey(Vendor, on_delete=models.CASCADE)
process = models.ForeignKey(ProcessType, on_delete=models.CASCADE)
def _get_full_name(self):
return self.process
full_name = property(_get_full_name)
def __str__(self):
return self.process.name
# Machines available for the process with the vendor
class VendorProcessMachine(BaseModel):
vendor_process = models.ForeignKey(VendorProcess, on_delete=models.CASCADE)
brand_name = models.CharField(max_length=100, blank=True)
accuracy = models.CharField(max_length=100, blank=True)
bed_size = models.CharField(max_length=100, blank=True)
year_of_manufacture = models.CharField(max_length=10, blank=True)
quantity = models.CharField(max_length=50, blank=True)
def __str__(self):
return self.brand_name
forms.py
from django import forms
from django.contrib.auth.forms import UserCreationForm
from django.forms import ModelForm, inlineformset_factory, formset_factory
from .models import User, Vendor, VendorMaterial, VendorProcess, VendorProcessMachine
class VendorSignupForm(UserCreationForm):
first_name = forms.CharField(max_length=100, label="Name")
mobile_no = forms.CharField(max_length=12)
address = forms.CharField(max_length=100)
gst = forms.CharField(max_length=12)
username = forms.EmailField(max_length=64,label="Email")
class Meta(UserCreationForm.Meta):
model = User
fields = ("first_name", "address", "username", "mobile_no","password1","password2", "gst")
exclude = ()
class VendorMaterialForm(ModelForm):
class Meta:
model = VendorMaterial
fields = ("material",)
class VendorProcessForm(ModelForm):
class Meta:
model = VendorProcess
fields = ('process',)
class VendorProcessMachineForm(ModelForm):
class Meta:
model = VendorProcessMachine
fields = ("brand_name", "accuracy", "bed_size", "year_of_manufacture", "quantity")
VendorMaterialFormset = inlineformset_factory(Vendor, VendorMaterial, can_delete = False, extra=1, form=VendorMaterialForm)
VendorProcessFormset = inlineformset_factory(Vendor, VendorProcess, extra=1, can_delete=False, form=VendorProcessForm)
VendorProcessMachineFormset = inlineformset_factory(VendorProcess, VendorProcessMachine, extra=1, can_delete=False, form=VendorProcessMachineForm)
views.py
# view.py
class VendorSignUpView(CreateView):
model = User
form_class =VendorSignupForm
template_name = 'signup.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
if self.request.POST:
context['vendor_material_formset'] = VendorMaterialFormset(self.request.POST, prefix="vendor_material_formset")
context['vendor_process_formset'] = VendorProcessFormset(self.request.POST, prefix="vendor_process_formset")
context['vendor_process_machine_formset'] = VendorProcessMachineFormset(self.request.POST, prefix="vendor_process_machine_formset")
else:
context['vendor_material_formset'] = VendorMaterialFormset(prefix="vendor_material_formset")
context['vendor_process_formset'] = VendorProcessFormset(prefix="vendor_process_formset")
context['vendor_process_machine_formset'] = VendorProcessMachineFormset(prefix="vendor_process_machine_formset")
return context
def form_valid(self, form):
context = self.get_context_data()
vendor_material = context['vendor_material_formset']
user = form.save(commit=False)
user.is_vendor = True
user.is_staff = True
user.email = form.cleaned_data.get('username')
user=form.save()
data = form.cleaned_data
vendor = Vendor.objects.create(user=user, address=data['address'], mobile_no=data['mobile_no'],
gst=data['gst'])
# Save
with transaction.atomic():
if vendor_material.is_valid():
print(vendor_material)
vendor_material.instance = vendor
vendor_material.save()
# Vendor Process machine
login(self.request, user)
return redirect('home')
template.html
{% extends 'base.html' %}
{% load static %}
{% block content %}
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="{% static 'formset/jquery.formset.js' %}"></script>
<h2>Sign up</h2>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<table class="table">
<div class="">
{{ vendor_material_formset.management_form }}
{% for vendor_material in vendor_material_formset %}
<fieldset class="vendor_material_row">
<legend>Material</legend>
{{ vendor_material.as_p }}
</fieldset>
{% endfor %}
</div>
</table>
<hr>
<table>
<div>
{{vendor_process_formset.management_form}}
{% for vendor_process in vendor_process_formset %}
<fieldset class="vendor_process_row">
<legend>Vendor Process</legend>
{{ vendor_process.as_p }}
{{vendor_process_machine_formset.management_form}}
<legend>Vendor Process Machine</legend>
{% for vendor_process_machine in vendor_process_machine_formset %}
<fieldset class="vendor_process_machine_row">
{{ vendor_process_machine.as_p }}
</fieldset>
{% endfor %}
</fieldset>
{%endfor%}
</div>
</table>
<input type="submit" name="submit" />
</form>
<script>
$('.vendor_material_row').formset({
addText: 'Add Material',
deleteText: 'Remove ',
prefix: 'vendor_material_formset'
});
$('.vendor_process_row').formset({
addText: 'Add Process',
deleteText: 'Remove Process ',
prefix: 'vendor_process_formset'
});
$('.vendor_process_machine_row').formset({
addText: 'Add Process Machine',
deleteText: 'Remove Process Machine',
prefix: 'vendor_process_machine_formset'
});
</script>
{% endblock %}