A new Workorder
is created by visiting the Building
page and creating a Work Order. This in turn displays the WorkOrderForm
on a new page.
When viewing this form, I want to display only the equipment associated to a building, not all of the equipment.
I have tried overriding the __init__
of the form to set the queryset
of the MultipleChoiceField
, which works as intended in displaying the equipment associated to the building, however when submitting the form the form.is_valid()
fail yet there are no errors displayed.
I have 3 models Building
, WorkOrder
and Equipment
as follows:
Building
class BuildingDetail(models.Model):
location_Code = models.CharField(primary_key=True, max_length=15, help_text='Enter a location code.', unique=True)
civic_Address = models.CharField(max_length=100, help_text='Enter the civic address of the location.')
current_Tenant = models.ForeignKey(Tenant, on_delete=models.CASCADE, help_text='Select a Tenant.')
landlord = models.ForeignKey(Landlord, on_delete=models.CASCADE, help_text='Select a Landlord.')
WorkOrder
class WorkOrder(models.Model):
id = models.CharField(primary_key=True, max_length=7, default=increment_workorder, verbose_name="ID")
building_Code = models.ForeignKey(BuildingDetail, on_delete=models.CASCADE)
issue_Date = models.DateField(blank=True, null=True, default=datetime.date.today())
completion_Date = models.DateField(blank=True, null=True)
tenant_Issue = models.TextField(help_text="Enter the issue description.")
scope_Of_Work = models.TextField(help_text="Enter the Scope of Work required.")
contact_name = models.CharField(max_length=50, help_text='Enter the contact Name.', blank=True, default="")
contact_number = models.CharField(max_length=11, help_text='Enter the contact Phone Number.', blank=True, default="")
rebill_Invoice = models.TextField(max_length=50, help_text='Enter the Devco Rebill Invoice number.', blank=True, default="")
rebill_Date = models.TextField(blank=True, null=True)
tenant = models.ForeignKey(Tenant, on_delete=models.CASCADE, null=True)
equipment = models.ManyToManyField(Equipment, blank=True, null=True, help_text='Select Equipment associated to this work order. Hold CTRL to select multiple.')
Equipment
class Equipment(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, help_text='Unique ID for equipment.')
name = models.CharField(max_length=150, help_text='Enter a name for this piece of equipment.')
make = models.CharField(max_length=100, blank=True, help_text='Enter the Make of the item.')
model = models.CharField(max_length=100, blank=True, help_text='Enter the model of the item.')
serial = models.CharField(max_length=100, blank=True, help_text='Enter the serial number of the item.')
cost = models.DecimalField(max_digits=15, decimal_places=2, help_text='Enter the cost before GST.', blank=True, default=0)
building = models.ForeignKey(BuildingDetail, on_delete=models.CASCADE)
Forms.py
class WorkOrderForm(ModelForm):
class Meta:
model = WorkOrder
fields = '__all__'
widgets = {
"issue_Date": DatePickerInput(),
"completion_Date": DatePickerInput(),
}
def __init__(self, *args, **kwargs):
building = kwargs.pop('building', None)
super(WorkOrderForm, self).__init__(**kwargs)
self.fields['equipment'].queryset = Equipment.objects.filter(building__location_Code=building)
Views.py
def CreateWorkOrder(request, building_code):
if building_code == "none":
workOrderForm = WorkOrderForm()
associatedCostsForm = AssociatedCostsForm()
context = {
'workOrderForm': workOrderForm,
'associatedCostsForm': associatedCostsForm,
}
else:
building = BuildingDetail.objects.get(location_Code=building_code)
equipment = Equipment.objects.filter(building=building)
currentTenant = building.current_Tenant
workOrderForm = WorkOrderForm(building=building_code, initial={
'building_Code': building,
'tenant': currentTenant})
associatedCostsForm = AssociatedCostsForm()
context = {
'workOrderForm': workOrderForm,
'associatedCostsForm': associatedCostsForm,
'building_code': building_code,
'building': building,
}
if request.method == "POST":
form = WorkOrderForm(request.POST)
if 'submit-workorder' in request.POST:
if form.is_valid():
form.clean()
workorder = form.save(commit=False)
workorder.save()
added_workorder = WorkOrder.objects.get(id=workorder.id)
building = added_workorder.building_Code
print(added_workorder)
print("You have submitted a Work Order.")
return redirect('view_building', building)
else:
print(form.errors)
return render(request, 'workorders\\workorder_form.html', context)
CodePudding user response:
You forgot to pass the *args
to the super init, which will contain the request.POST
data:
class WorkOrderForm(ModelForm):
class Meta:
model = WorkOrder
fields = '__all__'
widgets = {
'issue_Date': DatePickerInput(),
'completion_Date': DatePickerInput(),
}
def __init__(self, *args, **kwargs):
building = kwargs.pop('building', None)
super().__init__(*args, **kwargs)
self.fields['equipment'].queryset = Equipment.objects.filter(
building__location_Code=building
)
or perhaps simpler:
class WorkOrderForm(ModelForm):
class Meta:
model = WorkOrder
fields = '__all__'
widgets = {
'issue_Date': DatePickerInput(),
'completion_Date': DatePickerInput(),
}
def __init__(self, *args, building=None, **kwargs):
super().__init__(*args, **kwargs)
self.fields['equipment'].queryset = Equipment.objects.filter(
building__location_Code=building
)
For the view logic, the form should save the object, since then it also saves the many-to-many fields, so:
if request.method == 'POST' and 'submit-workorder' in request.POST:
form = WorkOrderForm(request.POST)
if form.is_valid():
workorder = form.save()
Note: Since PEP-3135 [pep], you don't need to call
super(…)
with parameters if the first parameter is the class in which you define the method, and the second is the first parameter (usuallyself
) of the function.