Ok I’m still a noob in Django, but i have an issue whereby I am creating objects from a formset that is based off ANOTHER different model. Basically in my template I have rendered 1 form from the PurchaseOrder Model, and 1 formset from the Purchase order item model. When I post it to my view for validation by forms.py, my PurchaseOrderForm validates fine, but my formset can’t seem to validate the 'ID’s. Basically my IDs of the forms in the formset correspond to the IDs of my RequisitionOrderItems Objects that i am making the purchase order items from. When I print my formset data from my POST request, I should have every data required for validation.
Here is my form_valid method of my CreateView that I am using:
def form_valid(self, form):
selected_item_ids = self.request.POST.getlist('po_select')
print("Selected Item IDs:", selected_item_ids)
# Fetch the outstanding requisition quantities dynamically
outstanding_qty_map = {
item.id: item.outstanding_requisition_qty
for item in RequisitionOrderItem.objects.with_outstanding_requisition_qty().filter(
id__in=selected_item_ids
)
}
# Map from requisition items to base inventory items
base_inventory_ids = RequisitionOrderItem.objects.filter(id__in=selected_item_ids).values_list('item_id', flat=True)
# Fetch supplier products by base inventory items
supplier_id = self.request.POST.get('supplier')
supplier_products_by_item = {}
if supplier_id:
supplier_products = SupplierProduct.objects.filter(
supplier_id=supplier_id,
item_id__in=base_inventory_ids
)
for base_inventory_id in base_inventory_ids:
supplier_products_by_item[base_inventory_id] = supplier_products.filter(item_id=base_inventory_id)
queryset = RequisitionOrderItem.objects.filter(id__in=selected_item_ids)
print("Requisition Items for Queryset:")
for item in queryset:
print(f"ID: {item.id}, Name: {item}")
# Recreate the formset with the POST data
formset = PurchaseOrderItemFormSet(
data=self.request.POST,
queryset=queryset,
form_kwargs={
'outstanding_qty_map': outstanding_qty_map,
'supplier_products_by_item': supplier_products_by_item,
}
)
# Debugging ID field querysets
for i, subform in enumerate(formset.forms):
if 'id' in subform.fields:
print(f"Form {i} ID Field Queryset: {list(subform.fields['id'].queryset)}")
else:
print(f"Form {i} does not have an 'id' field.")
# Print raw data for each form in the formset
print("Formset Raw Data Per Form:")
for i, subform in enumerate(formset.forms): # Iterate through all forms
form_prefix = subform.prefix # Get the prefix for this form
form_data = {
key: value
for key, value in self.request.POST.items()
if key.startswith(form_prefix)
}
print(f"Form {i} raw data:", form_data)
if f'{form_prefix}-id' in form_data:
print(f"Form {i} ID Value: {form_data[f'{form_prefix}-id']} (Type: {type(form_data[f'{form_prefix}-id'])})")
# Check if formset is valid
if formset.is_valid():
print("Formset is valid!")
else:
print("Formset is invalid. Errors:", formset.errors)
return self.render_to_response(self.get_context_data(form=form, formset=formset))
And below here are my forms.py
class PurchaseOrderItemForm(forms.ModelForm):
class Meta:
model = PurchaseOrderItem
fields = ['item', 'qty_ordered', 'product']
def __init__(self, *args, **kwargs):
# Extract custom arguments
self.outstanding_qty_map = kwargs.pop('outstanding_qty_map', {})
supplier_products_by_item = kwargs.pop('supplier_products_by_item', {})
# Call the parent class's __init__ method with remaining kwargs
super().__init__(*args, **kwargs)
# Apply Bootstrap classes to fields
for field_name, field in self.fields.items():
field.widget.attrs.update({'class': 'form-control'})
field.label = '' # Remove label
field.help_text = '' # Remove help text
# Disable 'item' field to make it HiddenInput
self.fields['item'].widget = HiddenInput()
# Dynamically filter the 'product' field's queryset
base_inventory_id = self.initial.get('item') # BaseInventory ID passed in initial data
if base_inventory_id in supplier_products_by_item:
self.fields['product'].queryset = supplier_products_by_item[base_inventory_id]
else:
self.fields['product'].queryset = SupplierProduct.objects.none()
# Create a formset factory for PurchaseOrderItem
PurchaseOrderItemFormSet = modelformset_factory(
PurchaseOrderItem,
form=PurchaseOrderItemForm,
extra=0,
can_delete=True
)
And Here below are my print statements:
Selected Item IDs: ['332', '333', '334']
Requisition Items for Queryset:
ID: 332, Name: Carrots
ID: 333, Name: Chili
ID: 334, Name: Garlic Paste
Form 0 ID Field Queryset: []
Form 1 ID Field Queryset: []
Form 2 ID Field Queryset: []
Formset Raw Data Per Form:
Form 0 raw data: {'form-0-id': '332', 'form-0-item': '1', 'form-0-qty_ordered': '2', 'form-0-product': '4'}
Form 0 ID Value: 332 (Type: <class 'str'>)
Form 1 raw data: {'form-1-id': '333', 'form-1-item': '3', 'form-1-qty_ordered': '2', 'form-1-product': '2'}
Form 1 ID Value: 333 (Type: <class 'str'>)
Form 2 raw data: {'form-2-id': '334', 'form-2-item': '4', 'form-2-qty_ordered': '2', 'form-2-product': '3'}
Form 2 ID Value: 334 (Type: <class 'str'>)
Formset is invalid. Errors: [{'id': ['Select a valid choice. That choice is not one of the available choices.']}, {'id': ['Select a valid choice. That choice is not one of the available choices.']}, {'id': ['Select a valid choice. That choice is not one of the available choices.']}]
Now from what i can see from my print statements, i get the feeling that the model defined in my forms.py is PurchaseOrderItem, but my queryset when initializing the formset in form_valid, uses RequisitionOrderItem. But my question is mainly how can i just skip or bypass the id validation for this since I am creating NEW purchase order items based on the requisition order items IDs submitted in the formset data? Should I even skip it? Any advice would be greatly appreciated!