HH/docs/JOURNEYS_FIELD_ERROR_FIX.md
2026-01-24 15:27:30 +03:00

247 lines
7.2 KiB
Markdown

# 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:
1. Use `select_related('created_by')` in the `journey_template_detail` view
2. Set `template.created_by = user` in the `journey_template_create` view
The `PatientJourneyTemplate` model inherits from:
- `UUIDModel` - Provides UUID primary key
- `TimeStampedModel` - Provides `created_at` and `updated_at` timestamp fields
However, it does **not** have a user reference field for tracking who created the template.
## Model Structure
```python
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:**
```python
@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:**
```python
@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:**
```python
@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:**
```python
@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
1. **apps/journeys/ui_views.py** - Line 279
- Removed `'created_by'` from `select_related()` call in `journey_template_detail`
- Changed from: `select_related('hospital', 'created_by')`
- Changed to: `select_related('hospital')`
2. **apps/journeys/ui_views.py** - Line 187
- Removed `template.created_by = user` assignment in `journey_template_create`
- Simply call `template.save()` without setting `created_by`
## 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_at` and `updated_at` from `TimeStampedModel`
- **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:
```python
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_by` and `updated_by` fields appropriately
## Testing
### Test Journey Template Detail Page
1. Navigate to: `http://localhost:8000/journeys/templates/<template-id>/`
2. Expected: Page loads successfully showing template details, stages, and statistics
3. Should see:
- Template information
- List of stages
- Statistics (total, active, completed instances)
### Test Journey Template Creation
1. Navigate to: `http://localhost:8000/journeys/templates/create/`
2. Fill in template form
3. Add stages
4. Submit
5. Expected: Template created successfully, redirect to detail page
## Related Files
- `apps/journeys/models.py` - Model definitions
- `apps/journeys/ui_views.py` - UI views (fixed)
- `apps/journeys/admin.py` - Admin interface
- `apps/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:
```python
# ✅ 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:
```python
# ✅ 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:
```python
# 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:**
1. Removed `created_by` from `select_related()` call
2. Removed `template.created_by = user` assignment
**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