partirdezero/courses/views.py

118 lines
No EOL
3.8 KiB
Python

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)