Home > Enterprise >  Form not valid after setting QuerySet of field in __init__
Form not valid after setting QuerySet of field in __init__

Time:11-06

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 (usually self) of the function.

  • Related