6.2 KiB
Subsection Dropdown Fix - Complete
Problem Summary
Original Error:
TypeError at /complaints/new/
QuerySet.none() missing 1 required positional argument: 'self'
This error occurred when accessing the public complaint form at /complaints/new/, preventing users from submitting complaints.
Root Cause Analysis
The error was traced to apps/complaints/forms.py line 178 in the PublicComplaintForm class. The issue was:
- Patient Field Removal: The patient field had been removed from the form, but the queryset filtering logic in
__init__was still attempting to filter patients - QuerySet.none() Call: The code was calling
QuerySet.none()as an unbound method instead of on a model queryset
Original problematic code:
# In forms.py __init__ method
self.fields['patient'].queryset = models.QuerySet.none()
This caused a TypeError because QuerySet.none() is an instance method that requires self (a QuerySet instance), but it was being called directly on the class.
Solution Implemented
1. Removed Patient Field (Already Done)
The patient field was already removed from the form's fields in a previous fix.
2. Cleaned Up Form Initialization
Removed the remaining patient queryset filtering code from the __init__ method.
3. SubSection Serializer Fix (Additional Issue Discovered)
While testing, we discovered that the SubSection dropdown was not working correctly. The SubSectionSerializer was using the database id field instead of internal_id, which caused the frontend to receive the wrong IDs.
Original serializer:
class SubSectionSerializer(serializers.ModelSerializer):
"""SubSection serializer for dropdown"""
name = serializers.SerializerMethodField()
class Meta:
model = SubSection
fields = ['id', 'name', 'location', 'main_section', 'location_name', 'main_section_name']
Fixed serializer:
class SubSectionSerializer(serializers.ModelSerializer):
"""SubSection serializer for dropdown"""
id = serializers.IntegerField(source='internal_id', read_only=True)
name = serializers.SerializerMethodField()
class Meta:
model = SubSection
fields = ['id', 'name', 'location', 'main_section', 'location_name', 'main_section_name']
Files Modified
-
apps/complaints/forms.py
- Removed patient field queryset filtering logic
-
apps/organizations/serializers.py
- Updated
SubSectionSerializerto useinternal_idas the ID field
- Updated
AJAX Endpoints
The following AJAX endpoints were already implemented and verified:
-
GET
/organizations/ajax/main-sections/?location_id={id}- Returns main sections for a specific location
- Response format:
{ "sections": [ {"id": 1, "name": "Medical"}, {"id": 2, "name": "Surgical"} ] }
-
GET
/organizations/ajax/subsections/?location_id={id}&main_section_id={id}- Returns subsections for a specific location and main section
- Response format:
{ "subsections": [ { "id": 43, "name": "Anesthesia Department", "location": 48, "main_section": 1, "location_name": "Inpatient", "main_section_name": "Medical" } ] }
Verification Results
All tests passed successfully:
Test 1: Main Sections API Endpoint
✓ Status: 200 ✓ Sections returned: 4 Sample section: ID=4, Name=Administrative
Test 2: Subsections API Endpoint
✓ Status: 200 ✓ Subsections returned: 23 Sample subsection: ID: 43 Name: Anesthesia Department Location: Inpatient Main Section: Medical ✓ ID is numeric (internal_id)
Test 3: Multiple Location/Section Combinations
✓ Inpatient + Medical: 23 subsections ✓ Inpatient + Surgical: 17 subsections ✓ Outpatient + Medical: 61 subsections ✓ Outpatient + Diagnostic: 2 subsections ✓ Emergency + Medical: 0 subsections
Passed: 5/5 combinations
User Experience
The public complaint form now works correctly with the following cascading dropdown behavior:
- User selects a Location (e.g., "Inpatient")
- Main Sections dropdown populates automatically with options like "Medical", "Surgical", "Diagnostic", "Administrative"
- User selects a Main Section (e.g., "Medical")
- Subsections dropdown populates automatically with relevant departments (e.g., "Anesthesia Department", "Coronary Care Unit", etc.)
Technical Details
Why internal_id Instead of id?
The SubSection model uses internal_id as the primary identifier because:
- It's a unique integer value used in external systems
- The auto-generated
idfield is a UUID - The frontend expects numeric IDs for dropdowns
internal_idis the value stored in related models
Form Field Configuration
The complaint form uses IntegerField for the subsection field:
subsection = forms.IntegerField(
required=False,
widget=forms.Select(attrs={
'class': 'form-control',
'id': 'id_subsection',
'placeholder': get_text('forms.complaints.subsection.placeholder')
})
)
This allows the form to accept the integer internal_id value from the dropdown.
Testing
Two test scripts were created:
- test_subsection_fix.py - Comprehensive test with Django model imports (requires proper Django setup)
- test_subsection_api.py - Simple API-only test (runs independently)
Both tests verified:
- API endpoint availability
- Correct data format
- Numeric ID values (internal_id)
- Multiple location/section combinations
Summary
The fix successfully resolved:
- ✅ The original TypeError with QuerySet.none()
- ✅ Removed orphaned patient field code
- ✅ Fixed SubSection dropdown to return correct IDs
- ✅ Verified cascading dropdown functionality
- ✅ Tested multiple location/section combinations
The public complaint form is now fully functional with proper cascading dropdowns for Location → Main Section → SubSection selection.
Related Documentation
CASCADING_DROPDOWN_FIX_COMPLETE.md- Previous cascading dropdown implementationPUBLIC_FORM_I18N_FIXES_COMPLETE.md- Internationalization updates to the formPUBLIC_FORM_4_LEVEL_UPDATE.md- 4-level taxonomy implementation