Configuración de Rutas
Para exponer los recursos de nuestra API, utilizamos el sistema de enrutamiento de Django REST Framework para registrar los ViewSets de categorías y cursos.
from rest_framework.routers import DefaultRouter
from . import views
router = DefaultRouter()
router.register('categorias', views.CategoryViewSet, basename='course-categories')
router.register('catalogo', views.AcademyCourseViewSet, basename='course-list')
Definición de Vistas y Lógica de Filtrado
El siguiente ViewSet gestiona la recuperación de cursos, integrando capacidades de búsqueda, ordenación y filtrado avanzado mediante el uso de django-filter.
from rest_framework.viewsets import GenericViewSet
from rest_framework.mixins import ListModelMixin
from rest_framework.filters import SearchFilter, OrderingFilter
from django_filters.rest_framework import DjangoFilterBackend
from . import models, serializers, pagination, filters
class CategoryViewSet(GenericViewSet, ListModelMixin):
"""
Vista para listar las categorías de cursos activas.
"""
queryset = models.CourseCategory.objects.filter(is_delete=False, is_show=True)
serializer_class = serializers.CategorySerializer
class AcademyCourseViewSet(GenericViewSet, ListModelMixin):
"""
Vista principal para el catálogo de cursos con soporte para paginación y filtros.
"""
queryset = models.AcademyCourse.objects.filter(is_delete=False, is_show=True)
serializer_class = serializers.AcademyCourseSerializer
pagination_class = pagination.StandardPagination
# Configuración de motores de filtrado
filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
# Campos habilitados para búsqueda y ordenación
search_fields = ['title', 'description']
ordering_fields = ['id', 'price', 'enrolled_students']
# Clase personalizada para filtros de rango
filterset_class = filters.CourseRangeFilter
Filtros Personalizados de Rango
Implementamos una clase de filtrado para permitir a los usuarios buscar cursos dentro de un rango de precios específico.
from django_filters import rest_framework as filters
from .models import AcademyCourse
class CourseRangeFilter(filters.FilterSet):
coste_min = filters.NumberFilter(field_name='price', lookup_expr='gte')
coste_max = filters.NumberFilter(field_name='price', lookup_expr='lte')
class Meta:
model = AcademyCourse
fields = ['category', 'coste_min', 'coste_max']
Esquema de Paginación
Definimos una estructura de pgainación personalizada para controlar el volumen de datos enviados al cliente por cada solicitud.
from rest_framework.pagination import PageNumberPagination
class StandardPagination(PageNumberPagination):
page_size = 5 # Cantidad por defecto
page_query_param = 'p'
page_size_query_param = 'limit'
max_page_size = 20
Lógica en el Modelo y Propiedades Dinámicas
En el modelo de datos, utilizamos el decorador @property para generar campos calculados que facilitan la serialización de datos complejos, como la vista previa de las lecciones.
from django.db import models
class AcademyCourse(BaseModel):
# ... campos del modelo ...
@property
def label_type(self):
return self.get_course_type_display()
@property
def preview_lessons(self):
"""
Retorna una lista con las primeras 4 lecciones de todos los capítulos.
"""
items = []
for chapter in self.chapters.all():
for lesson in chapter.lessons.all():
items.append({
'title': lesson.name,
'url': lesson.video_url,
'duration': lesson.length,
'is_free': lesson.is_preview,
})
if len(items) >= 4:
return items
return items
class Instructor(BaseModel):
# ... campos del modelo ...
@property
def profession(self):
return self.get_role_display()
Serialización de Datos
Finalmente, configuramos los serializadores para transformar los modelos en formato JSON, encluyendo la anidación del instructor dentro de cada curso.
from rest_framework import serializers
from . import models
class CategorySerializer(serializers.ModelSerializer):
class Meta:
model = models.CourseCategory
fields = ('id', 'name')
class InstructorSerializer(serializers.ModelSerializer):
role = serializers.ReadOnlyField(source='profession')
class Meta:
model = models.Instructor
fields = ('name', 'role', 'biography', 'avatar')
class AcademyCourseSerializer(serializers.ModelSerializer):
teacher_info = InstructorSerializer(source='instructor', read_only=True)
type_display = serializers.ReadOnlyField(source='label_type')
lessons_list = serializers.ReadOnlyField(source='preview_lessons')
class Meta:
model = models.AcademyCourse
fields = (
'id', 'title', 'cover_image', 'price',
'enrolled_students', 'type_display',
'teacher_info', 'lessons_list'
)