6.1 KiB
Complaint Form Fix Summary
Issue
The complaint form at /complaints/new/ was failing with a TypeError due to incorrect usage of QuerySet.none().
Root Causes
- TypeError:
QuerySet.none()was being called as a class method instead of an instance method - FieldError: The form was trying to order by
namefield, but Location/MainSection/SubSection models usename_enfor the display name - Missing Fields: The ComplaintForm was missing new fields added to the Complaint model
Changes Made
1. Fixed apps/complaints/forms.py
PublicComplaintForm (Line 178)
Before:
queryset=models.QuerySet.none(),
After:
queryset=Department.objects.none(),
Initialize Cascading Dropdown Querysets
Problem: The main_section and subsection fields had queryset=None initially, causing:
'NoneType' object has no attribute '_prefetch_related_lookups'
Solution: Added initialization in __init__ method for both ComplaintForm and PublicComplaintForm:
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
from apps.organizations.models import Location, MainSection, SubSection
# Initialize cascading dropdowns with empty querysets
self.fields['main_section'].queryset = MainSection.objects.none()
self.fields['subsection'].queryset = SubSection.objects.none()
# Load all locations (no filtering needed)
self.fields['location'].queryset = Location.objects.all().order_by('name_en')
Added ComplaintType Import
from apps.complaints.models import (
Complaint,
ComplaintCategory,
ComplaintSource,
ComplaintStatus,
ComplaintType, # Added
Inquiry,
ComplaintSLAConfig,
EscalationRule,
ComplaintThreshold,
)
Updated ComplaintForm with New Fields
Added the following fields to ComplaintForm class:
complaint_type- Feedback type selection (Complaint/Appreciation)relation_to_patient- Patient or Relativepatient_name- Name of patient involvednational_id- Saudi National ID or Iqama numberincident_date- Date when incident occurredstaff_name- Staff member involved (if known)expected_result- Expected resolution from complainant
Fixed Field Ordering
Changed all .order_by('name') to .order_by('name_en') for Location, MainSection, and SubSection querysets to match the actual field names in the models.
2. Updated templates/complaints/complaint_form.html
New Sections Added:
-
Feedback Type Selection
- Visual cards for Complaint vs Appreciation selection
- Interactive JavaScript handlers for selection
-
Patient Information Section
- Relation to Patient dropdown
- Patient Name field
- National ID/Iqama field
- Incident Date field
- Encounter ID field (optional)
-
Organization & Location Section
- Hospital dropdown
- Department dropdown
- Location hierarchy (Location → Main Section → Subsection)
- Staff dropdown (optional)
- Staff Name field (optional)
-
Complaint Details Section
- Description field
- Expected Result field
-
Enhanced JavaScript
- Complaint type card selection handlers
- Hospital change handler (reloads form)
- Location change handler (loads sections via AJAX)
- Main Section change handler (loads subsections via AJAX)
- Department change handler (loads staff via AJAX)
- Form validation
-
Updated Sidebar
- AI Classification information
- SLA Information display
- Action buttons
Model Fields Reference
Location Hierarchy Models
# Location model
name_en = models.CharField(max_length=200) # Display name
name_ar = models.CharField(max_length=200, blank=True)
# MainSection model
name_en = models.CharField(max_length=200) # Display name
name_ar = models.CharField(max_length=200, blank=True)
# SubSection model
name_en = models.CharField(max_length=200) # Display name
name_ar = models.CharField(max_length=200, blank=True)
Complaint Model New Fields
complaint_type = models.CharField(max_length=20, choices=ComplaintType.choices)
relation_to_patient = models.CharField(max_length=20)
patient_name = models.CharField(max_length=200)
national_id = models.CharField(max_length=20)
incident_date = models.DateField()
staff_name = models.CharField(max_length=200, blank=True)
expected_result = models.TextField(blank=True)
location = models.ForeignKey('organizations.Location')
main_section = models.ForeignKey('organizations.MainSection')
subsection = models.ForeignKey('organizations.SubSection')
Verification
✅ Form imports successfully without errors
✅ All new fields are properly defined
✅ Field ordering uses correct field names (name_en)
✅ Template includes all new form sections
✅ JavaScript handlers implemented for cascading dropdowns
✅ Internationalization support maintained (i18n)
Testing Checklist
- Form loads without errors at
/complaints/new/ - Location dropdown loads all locations
- Selecting location loads sections via AJAX
- Selecting section loads subsections via AJAX
- Complaint type selection works visually
- Form validation works for all required fields
- Form submission creates complaint with all new fields
- Patient information fields display correctly
- Staff dropdown loads when department is selected
Notes
-
AJAX Endpoints: The form relies on these AJAX endpoints:
/organizations/ajax/main-sections/?location_id={id}/organizations/ajax/subsections/?location_id={id}&main_section_id={id}/complaints/ajax/physicians/?department_id={id}
-
Location Hierarchy: The form implements a 3-level cascading dropdown system:
- Level 1: Location (e.g., Riyadh, Jeddah)
- Level 2: Main Section (e.g., Clinical, Administrative)
- Level 3: Subsection (e.g., Outpatient, Inpatient)
-
Complaint Type: The form supports both Complaint and Appreciation types with a visual card-based selection interface.
-
i18n Support: All labels and placeholders use Django's translation system (
_("text")) for multilingual support.
Date Completed
February 4, 2026