# Django Views & URL Analysis - Controller Pattern Mapping

**Date:** January 7, 2025  
**Analyst:** Roo (Architect Mode)  
**Purpose:** Django view/URL pattern analysis for Symfony controller conversion  
**Status:** Complete view layer analysis for conversion planning

## Overview

This document analyzes Django view patterns, URL routing, and controller logic to facilitate conversion to Symfony's controller and routing system. Focus on HTMX integration, authentication patterns, and RESTful designs.

## Django View Architecture Analysis

### View Types and Patterns

#### 1. Function-Based Views (FBV)
```python
# Example: Search functionality
def search_view(request):
    query = request.GET.get('q', '')
    
    if request.htmx:
        # Return HTMX partial
        return render(request, 'search/partials/results.html', {
            'results': search_results,
            'query': query
        })
    
    # Return full page
    return render(request, 'search/index.html', {
        'results': search_results,
        'query': query
    })
```

#### 2. Class-Based Views (CBV)
```python
# Example: Park detail view
class ParkDetailView(DetailView):
    model = Park
    template_name = 'parks/detail.html'
    context_object_name = 'park'
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['rides'] = self.object.rides.filter(status='OPERATING')
        context['photos'] = self.object.photos.filter(approval_status='APPROVED')
        context['reviews'] = self.object.reviews.filter(is_approved=True)[:5]
        return context
```

#### 3. HTMX-Enhanced Views
```python
# Example: Autocomplete endpoint
def park_autocomplete(request):
    query = request.GET.get('q', '')
    
    if not request.htmx:
        return JsonResponse({'error': 'HTMX required'}, status=400)
    
    parks = Park.objects.filter(
        name__icontains=query
    ).select_related('operator')[:10]
    
    return render(request, 'parks/partials/autocomplete.html', {
        'parks': parks,
        'query': query
    })
```

### Authentication & Authorization Patterns

#### 1. Decorator-Based Protection
```python
from django.contrib.auth.decorators import login_required, user_passes_test

@login_required
def submit_review(request, park_id):
    # Review submission logic
    pass

@user_passes_test(lambda u: u.role in ['MODERATOR', 'ADMIN'])
def moderation_dashboard(request):
    # Moderation interface
    pass
```

#### 2. Permission Checks in Views
```python
class ParkEditView(UpdateView):
    model = Park
    
    def dispatch(self, request, *args, **kwargs):
        if not request.user.is_authenticated:
            return redirect('login')
        
        if request.user.role not in ['MODERATOR', 'ADMIN']:
            raise PermissionDenied
        
        return super().dispatch(request, *args, **kwargs)
```

#### 3. Context-Based Permissions
```python
def park_detail(request, slug):
    park = get_object_or_404(Park, slug=slug)
    
    context = {
        'park': park,
        'can_edit': request.user.is_authenticated and 
                   request.user.role in ['MODERATOR', 'ADMIN'],
        'can_review': request.user.is_authenticated,
        'can_upload': request.user.is_authenticated,
    }
    
    return render(request, 'parks/detail.html', context)
```

## URL Routing Analysis

### Main URL Structure
```python
# thrillwiki/urls.py
urlpatterns = [
    path('admin/', admin.site.urls),
    path('', HomeView.as_view(), name='home'),
    path('parks/', include('parks.urls')),
    path('rides/', include('rides.urls')),
    path('operators/', include('operators.urls')),
    path('manufacturers/', include('manufacturers.urls')),
    path('designers/', include('designers.urls')),
    path('property-owners/', include('property_owners.urls')),
    path('search/', include('search.urls')),
    path('accounts/', include('accounts.urls')),
    path('ac/', include('autocomplete.urls')),  # HTMX autocomplete
    path('moderation/', include('moderation.urls')),
    path('history/', include('history.urls')),
    path('photos/', include('media.urls')),
]
```

### App-Specific URL Patterns

#### Parks URLs
```python
# parks/urls.py
urlpatterns = [
    path('', ParkListView.as_view(), name='park-list'),
    path('<slug:slug>/', ParkDetailView.as_view(), name='park-detail'),
    path('<slug:slug>/edit/', ParkEditView.as_view(), name='park-edit'),
    path('<slug:slug>/photos/', ParkPhotoListView.as_view(), name='park-photos'),
    path('<slug:slug>/reviews/', ParkReviewListView.as_view(), name='park-reviews'),
    path('<slug:slug>/rides/', ParkRideListView.as_view(), name='park-rides'),
    
    # HTMX endpoints
    path('<slug:slug>/rides/partial/', park_rides_partial, name='park-rides-partial'),
    path('<slug:slug>/photos/partial/', park_photos_partial, name='park-photos-partial'),
]
```

#### Search URLs
```python
# search/urls.py
urlpatterns = [
    path('', SearchView.as_view(), name='search'),
    path('suggestions/', search_suggestions, name='search-suggestions'),
    path('parks/', park_search, name='park-search'),
    path('rides/', ride_search, name='ride-search'),
]
```

#### Autocomplete URLs (HTMX)
```python
# autocomplete/urls.py  
urlpatterns = [
    path('parks/', park_autocomplete, name='ac-parks'),
    path('rides/', ride_autocomplete, name='ac-rides'),
    path('operators/', operator_autocomplete, name='ac-operators'),
    path('manufacturers/', manufacturer_autocomplete, name='ac-manufacturers'),
    path('designers/', designer_autocomplete, name='ac-designers'),
]
```

### SEO and Slug Management

#### Historical Slug Support
```python
# Custom middleware for slug redirects
class SlugRedirectMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response
    
    def __call__(self, request):
        response = self.get_response(request)
        
        if response.status_code == 404:
            # Check for historical slugs
            old_slug = request.path.split('/')[-2]  # Extract slug from path
            
            # Look up in slug history
            try:
                slug_history = SlugHistory.objects.get(old_slug=old_slug)
                new_url = request.path.replace(old_slug, slug_history.current_slug)
                return redirect(new_url, permanent=True)
            except SlugHistory.DoesNotExist:
                pass
        
        return response
```

## Form Handling Patterns

### Django Form Integration

#### 1. Model Forms
```python
# forms.py
class ParkForm(forms.ModelForm):
    class Meta:
        model = Park
        fields = ['name', 'description', 'website', 'operator', 'property_owner']
        widgets = {
            'description': forms.Textarea(attrs={'rows': 4}),
            'operator': autocomplete.ModelSelect2(url='ac-operators'),
            'property_owner': autocomplete.ModelSelect2(url='ac-property-owners'),
        }
    
    def clean_name(self):
        name = self.cleaned_data['name']
        # Custom validation logic
        return name
```

#### 2. HTMX Form Processing
```python
def park_form_view(request, slug=None):
    park = get_object_or_404(Park, slug=slug) if slug else None
    
    if request.method == 'POST':
        form = ParkForm(request.POST, instance=park)
        if form.is_valid():
            park = form.save()
            
            if request.htmx:
                # Return updated partial
                return render(request, 'parks/partials/park_card.html', {
                    'park': park
                })
            
            return redirect('park-detail', slug=park.slug)
    else:
        form = ParkForm(instance=park)
    
    template = 'parks/partials/form.html' if request.htmx else 'parks/form.html'
    return render(request, template, {'form': form, 'park': park})
```

#### 3. File Upload Handling
```python
def photo_upload_view(request):
    if request.method == 'POST':
        form = PhotoUploadForm(request.POST, request.FILES)
        if form.is_valid():
            photo = form.save(commit=False)
            photo.uploaded_by = request.user
            
            # Extract EXIF data
            if photo.image:
                photo.exif_data = extract_exif_data(photo.image)
            
            photo.save()
            
            if request.htmx:
                return render(request, 'media/partials/photo_preview.html', {
                    'photo': photo
                })
            
            return redirect('photo-detail', pk=photo.pk)
    
    return render(request, 'media/upload.html', {'form': form})
```

## API Patterns and JSON Responses

### HTMX JSON Responses
```python
def search_api(request):
    query = request.GET.get('q', '')
    
    results = {
        'parks': list(Park.objects.filter(name__icontains=query).values('name', 'slug')[:5]),
        'rides': list(Ride.objects.filter(name__icontains=query).values('name', 'slug')[:5]),
    }
    
    return JsonResponse(results)
```

### Error Handling
```python
def api_view_with_error_handling(request):
    try:
        # View logic
        return JsonResponse({'success': True, 'data': data})
    except ValidationError as e:
        return JsonResponse({'success': False, 'errors': e.message_dict}, status=400)
    except PermissionDenied:
        return JsonResponse({'success': False, 'error': 'Permission denied'}, status=403)
    except Exception as e:
        logger.exception('Unexpected error in API view')
        return JsonResponse({'success': False, 'error': 'Internal error'}, status=500)
```

## Middleware Analysis

### Custom Middleware Stack
```python
# settings.py
MIDDLEWARE = [
    'django.middleware.cache.UpdateCacheMiddleware',
    'django.middleware.security.SecurityMiddleware',
    'whitenoise.middleware.WhiteNoiseMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'core.middleware.PgHistoryContextMiddleware',  # Custom history context
    'allauth.account.middleware.AccountMiddleware',
    'django.middleware.cache.FetchFromCacheMiddleware',
    'django_htmx.middleware.HtmxMiddleware',  # HTMX support
    'analytics.middleware.PageViewMiddleware',  # Custom analytics
]
```

### Custom Middleware Examples

#### History Context Middleware
```python
class PgHistoryContextMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response
    
    def __call__(self, request):
        # Set context for history tracking
        with pghistory.context(
            user=getattr(request, 'user', None),
            ip_address=self.get_client_ip(request),
            user_agent=request.META.get('HTTP_USER_AGENT', '')
        ):
            response = self.get_response(request)
        
        return response
```

#### Page View Tracking Middleware
```python
class PageViewMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response
    
    def __call__(self, request):
        response = self.get_response(request)
        
        # Track page views for successful responses
        if response.status_code == 200 and not request.htmx:
            self.track_page_view(request)
        
        return response
```

## Context Processors

### Custom Context Processors
```python
# moderation/context_processors.py
def moderation_access(request):
    """Add moderation permissions to template context"""
    return {
        'can_moderate': (
            request.user.is_authenticated and 
            request.user.role in ['MODERATOR', 'ADMIN', 'SUPERUSER']
        ),
        'pending_submissions_count': (
            EditSubmission.objects.filter(status='PENDING').count()
            if request.user.is_authenticated and request.user.role in ['MODERATOR', 'ADMIN']
            else 0
        )
    }
```

## Conversion Mapping to Symfony

### View → Controller Mapping

| Django Pattern | Symfony Equivalent |
|----------------|-------------------|
| Function-based views | Controller methods |
| Class-based views | Controller classes |
| `@login_required` | Security annotations |
| `user_passes_test` | Voter system |
| `render()` | `$this->render()` |
| `JsonResponse` | `JsonResponse` |
| `redirect()` | `$this->redirectToRoute()` |
| `get_object_or_404` | Repository + exception |

### URL → Route Mapping

| Django Pattern | Symfony Equivalent |
|----------------|-------------------|
| `path('', view)` | `#[Route('/', name: '')]` |
| `<slug:slug>` | `{slug}` with requirements |
| `include()` | Route prefixes |
| `name='route-name'` | `name: 'route_name'` |

### Key Conversion Considerations

#### 1. HTMX Integration
```yaml
# Symfony equivalent approach
# Route annotations for HTMX endpoints
#[Route('/parks/{slug}/rides', name: 'park_rides')]
#[Route('/parks/{slug}/rides/partial', name: 'park_rides_partial')]
public function parkRides(Request $request, Park $park): Response
{
    $rides = $park->getRides();
    
    if ($request->headers->has('HX-Request')) {
        return $this->render('parks/partials/rides.html.twig', [
            'rides' => $rides
        ]);
    }
    
    return $this->render('parks/rides.html.twig', [
        'park' => $park,
        'rides' => $rides
    ]);
}
```

#### 2. Authentication & Authorization
```php
// Symfony Security approach
#[IsGranted('ROLE_MODERATOR')]
class ModerationController extends AbstractController
{
    #[Route('/moderation/dashboard')]
    public function dashboard(): Response
    {
        // Moderation logic
    }
}
```

#### 3. Form Handling
```php
// Symfony Form component
#[Route('/parks/{slug}/edit', name: 'park_edit')]
public function edit(Request $request, Park $park, EntityManagerInterface $em): Response
{
    $form = $this->createForm(ParkType::class, $park);
    $form->handleRequest($request);
    
    if ($form->isSubmitted() && $form->isValid()) {
        $em->flush();
        
        if ($request->headers->has('HX-Request')) {
            return $this->render('parks/partials/park_card.html.twig', [
                'park' => $park
            ]);
        }
        
        return $this->redirectToRoute('park_detail', ['slug' => $park->getSlug()]);
    }
    
    $template = $request->headers->has('HX-Request') 
        ? 'parks/partials/form.html.twig'
        : 'parks/form.html.twig';
        
    return $this->render($template, [
        'form' => $form->createView(),
        'park' => $park
    ]);
}
```

#### 4. Middleware → Event Listeners
```php
// Symfony event listener equivalent
class PageViewListener
{
    public function onKernelResponse(ResponseEvent $event): void
    {
        $request = $event->getRequest();
        $response = $event->getResponse();
        
        if ($response->getStatusCode() === 200 && 
            !$request->headers->has('HX-Request')) {
            $this->trackPageView($request);
        }
    }
}
```

## Template Integration Analysis

### Django Template Features
```html
<!-- Django template with HTMX -->
{% extends 'base.html' %}
{% load parks_tags %}

{% block content %}
<div hx-get="{% url 'park-rides-partial' park.slug %}" 
     hx-trigger="load">
    Loading rides...
</div>

{% if user.is_authenticated and can_edit %}
    <a href="{% url 'park-edit' park.slug %}" 
       hx-get="{% url 'park-edit' park.slug %}"
       hx-target="#edit-form">Edit Park</a>
{% endif %}
{% endblock %}
```

### Symfony Twig Equivalent
```twig
{# Twig template with HTMX #}
{% extends 'base.html.twig' %}

{% block content %}
<div hx-get="{{ path('park_rides_partial', {slug: park.slug}) }}" 
     hx-trigger="load">
    Loading rides...
</div>

{% if is_granted('ROLE_USER') and can_edit %}
    <a href="{{ path('park_edit', {slug: park.slug}) }}" 
       hx-get="{{ path('park_edit', {slug: park.slug}) }}"
       hx-target="#edit-form">Edit Park</a>
{% endif %}
{% endblock %}
```

## Next Steps for Controller Conversion

1. **Route Definition** - Convert Django URLs to Symfony routes
2. **Controller Classes** - Map views to controller methods
3. **Security Configuration** - Set up Symfony Security for authentication
4. **Form Types** - Convert Django forms to Symfony form types
5. **Event System** - Replace Django middleware with Symfony event listeners
6. **Template Migration** - Convert Django templates to Twig
7. **HTMX Integration** - Ensure seamless HTMX functionality in Symfony

---

**Status:** ✅ **COMPLETED** - View/controller pattern analysis for Symfony conversion  
**Next:** Template system analysis and frontend architecture conversion planning