from django.shortcuts import render, get_object_or_404, redirect from django.urls import reverse from django.views import generic from django.db.models import Prefetch from .models import Course, Lesson, Module, Comment from .forms import CommentForm def list_courses(request): courses = Course.objects.all() return render(request, 'courses/list.html', {'courses': courses}) def show(request, course_name, course_id): # Optimized course fetch with related author and profile (if present) course = get_object_or_404( Course.objects.select_related('author', 'author__profile'), pk=course_id, ) # Fetch lessons through module -> course relation and keep a stable order lessons = ( Lesson.objects.filter(module__course_id=course_id) .select_related('module') .order_by('order') ) context = { 'course': course, 'lessons': lessons, } return render(request, 'courses/show.html', context) def lesson_detail(request, course_slug, module_slug, lesson_slug): # Fetch course by slug course = get_object_or_404( Course.objects.select_related('author', 'author__profile'), slug=course_slug, ) # Fetch module within course module = get_object_or_404( Module.objects.filter(course=course), slug=module_slug, ) # Fetch lesson within module lesson = get_object_or_404( Lesson.objects.select_related('module').filter(module=module), slug=lesson_slug, ) # Handle comment submission if request.method == 'POST': if not request.user.is_authenticated: login_url = reverse('login') return redirect(f"{login_url}?next={request.path}") form = CommentForm(request.POST) if form.is_valid(): parent = None parent_id = form.cleaned_data.get('parent') if parent_id: try: parent = Comment.objects.get(id=parent_id, lesson=lesson, is_active=True) except Comment.DoesNotExist: parent = None Comment.objects.create( lesson=lesson, user=request.user, content=form.cleaned_data['content'], parent=parent, ) # Redirect to anchor to show the new comment return redirect(request.path + "#comments") else: form = CommentForm() # Lessons list for TOC (entire course ordered) lessons = ( Lesson.objects.filter(module__course=course) .select_related('module') .order_by('order') ) # Compute previous and next lessons within the ordered course lessons prev_lesson = None next_lesson = None try: ids = list(lessons.values_list('id', flat=True)) idx = ids.index(lesson.id) if idx > 0: prev_lesson = next(l for l in lessons if l.id == ids[idx - 1]) if idx < len(ids) - 1: next_lesson = next(l for l in lessons if l.id == ids[idx + 1]) except ValueError: # current lesson not in list — keep prev/next as None pass # Public comments for the current lesson (top-level) and their replies replies_qs = Comment.objects.filter(is_active=True).select_related('user').order_by('created_at') comments = ( Comment.objects.filter(lesson=lesson, is_active=True, parent__isnull=True) .select_related('user') .prefetch_related(Prefetch('replies', queryset=replies_qs)) .order_by('created_at') ) context = { 'course': course, 'module': module, 'lesson': lesson, 'lessons': lessons, 'comments': comments, 'comment_form': form, 'prev_lesson': prev_lesson, 'next_lesson': next_lesson, } return render(request, 'courses/lesson.html', context)