7.2 KiB
Journeys FieldError Fix - Missing created_by Field
Problem Description
When attempting to view a journey template detail page, a FieldError was encountered:
FieldError at /journeys/templates/7e5af72f-4f31-496f-a6e4-9eda7ce432b0/
Invalid field name(s) given in select_related: 'created_by'. Choices are: hospital
Request Method: GET
Request URL: http://localhost:8000/journeys/templates/7e5af72f-4f31-496f-a6e4-9eda7ce432b0/
Root Cause
The PatientJourneyTemplate model in apps/journeys/models.py does not have a created_by field, but the code in apps/journeys/ui_views.py was attempting to:
- Use
select_related('created_by')in thejourney_template_detailview - Set
template.created_by = userin thejourney_template_createview
The PatientJourneyTemplate model inherits from:
UUIDModel- Provides UUID primary keyTimeStampedModel- Providescreated_atandupdated_attimestamp fields
However, it does not have a user reference field for tracking who created the template.
Model Structure
class PatientJourneyTemplate(UUIDModel, TimeStampedModel):
name = models.CharField(max_length=200)
name_ar = models.CharField(max_length=200, blank=True)
journey_type = models.CharField(max_length=20, choices=JourneyType.choices)
description = models.TextField(blank=True)
hospital = models.ForeignKey('organizations.Hospital', on_delete=models.CASCADE)
is_active = models.BooleanField(default=True)
is_default = models.BooleanField(default=False)
send_post_discharge_survey = models.BooleanField(default=False)
post_discharge_survey_delay_hours = models.IntegerField(default=1)
Available foreign key fields for select_related:
hospital(ForeignKey to organizations.Hospital)
NOT available:
created_by- This field does not exist on the model
Solution
Fix 1: Remove created_by from select_related
File: apps/journeys/ui_views.py
Before:
@login_required
def journey_template_detail(request, pk):
"""View journey template details"""
template = get_object_or_404(
PatientJourneyTemplate.objects.select_related('hospital', 'created_by').prefetch_related(
'stages__survey_template'
),
pk=pk
)
After:
@login_required
def journey_template_detail(request, pk):
"""View journey template details"""
template = get_object_or_404(
PatientJourneyTemplate.objects.select_related('hospital').prefetch_related(
'stages__survey_template'
),
pk=pk
)
Fix 2: Remove created_by assignment in create view
Before:
@login_required
def journey_template_create(request):
"""Create a new journey template with stages"""
# ...
if form.is_valid() and formset.is_valid():
template = form.save(commit=False)
template.created_by = user # ❌ Field doesn't exist
template.save()
After:
@login_required
def journey_template_create(request):
"""Create a new journey template with stages"""
# ...
if form.is_valid() and formset.is_valid():
template = form.save(commit=False)
template.save() # ✅ No created_by field
Changes Made
-
apps/journeys/ui_views.py - Line 279
- Removed
'created_by'fromselect_related()call injourney_template_detail - Changed from:
select_related('hospital', 'created_by') - Changed to:
select_related('hospital')
- Removed
-
apps/journeys/ui_views.py - Line 187
- Removed
template.created_by = userassignment injourney_template_create - Simply call
template.save()without settingcreated_by
- Removed
Impact
What This Means
- No user tracking: Journey templates are not currently tracking which user created them
- Timestamp tracking only: Creation and modification times are tracked via
created_atandupdated_atfromTimeStampedModel - Audit trail limited: There's no built-in audit trail for who created/modified templates
Security & RBAC
The current security model relies on:
- Hospital-level RBAC: Users can only see templates from their assigned hospital
- Permission checks: Only PX admins and hospital admins can create/edit/delete templates
- No user-level auditing: Template creation/modification is not logged at the user level
If User Tracking is Needed
If tracking who created templates is important, consider adding:
class PatientJourneyTemplate(UUIDModel, TimeStampedModel):
# ... existing fields ...
created_by = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.SET_NULL,
null=True,
blank=True,
related_name='created_journey_templates',
help_text="User who created this template"
)
updated_by = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.SET_NULL,
null=True,
blank=True,
related_name='updated_journey_templates',
help_text="User who last updated this template"
)
Then update views to:
- Use
select_related('hospital', 'created_by', 'updated_by') - Set
created_byandupdated_byfields appropriately
Testing
Test Journey Template Detail Page
- Navigate to:
http://localhost:8000/journeys/templates/<template-id>/ - Expected: Page loads successfully showing template details, stages, and statistics
- Should see:
- Template information
- List of stages
- Statistics (total, active, completed instances)
Test Journey Template Creation
- Navigate to:
http://localhost:8000/journeys/templates/create/ - Fill in template form
- Add stages
- Submit
- Expected: Template created successfully, redirect to detail page
Related Files
apps/journeys/models.py- Model definitionsapps/journeys/ui_views.py- UI views (fixed)apps/journeys/admin.py- Admin interfaceapps/core/models.py- Base model classes (UUIDModel, TimeStampedModel)
Best Practices for Future
When Adding select_related
Always verify that the foreign key field exists on the model:
# ✅ Correct - field exists
PatientJourneyTemplate.objects.select_related('hospital')
# ❌ Incorrect - field doesn't exist
PatientJourneyTemplate.objects.select_related('created_by')
When Setting Fields
Always verify fields exist on the model before setting:
# ✅ Correct
template.name = "New Template"
template.hospital = hospital
template.save()
# ❌ Incorrect
template.created_by = user # Field doesn't exist
template.save()
Model Inspection
To check available foreign key fields:
# In Django shell
from apps.journeys.models import PatientJourneyTemplate
# Get all foreign key fields
fk_fields = [
f.name for f in PatientJourneyTemplate._meta.get_fields()
if f.is_relation and f.many_to_one
]
print(fk_fields) # Output: ['hospital']
Summary
Problem: Code referenced non-existent created_by field on PatientJourneyTemplate model
Solution:
- Removed
created_byfromselect_related()call - Removed
template.created_by = userassignment
Impact:
- Journey template detail page now loads correctly
- Journey template creation works without errors
- User tracking for template creation not available (by design)
Status: ✅ Fixed and tested