5 changed files with 233 additions and 2 deletions
-
18apps/podcast/migrations/0002_podcast_collections.py
-
2apps/podcast/models.py
-
130apps/podcast/serializers_admin.py
-
12apps/podcast/urls.py
-
73apps/podcast/views_admin.py
@ -0,0 +1,18 @@ |
|||
# Generated by Django 5.2.12 on 2026-06-08 14:02 |
|||
|
|||
from django.db import migrations, models |
|||
|
|||
|
|||
class Migration(migrations.Migration): |
|||
|
|||
dependencies = [ |
|||
('podcast', '0001_initial'), |
|||
] |
|||
|
|||
operations = [ |
|||
migrations.AddField( |
|||
model_name='podcast', |
|||
name='collections', |
|||
field=models.ManyToManyField(blank=True, related_name='podcasts', to='podcast.podcastcollection', verbose_name='collections'), |
|||
), |
|||
] |
|||
@ -0,0 +1,130 @@ |
|||
from rest_framework import serializers |
|||
|
|||
from .models import Podcast , PodcastCategory , PodcastCollection |
|||
|
|||
|
|||
class AbsoluteImageField(serializers.ImageField): |
|||
def to_representation(self, value): |
|||
if not value: |
|||
return None |
|||
request = self.context.get("request") |
|||
url = value.url if hasattr(value, "url") else str(value) |
|||
if request: |
|||
return request.build_absolute_uri(url) |
|||
return url |
|||
|
|||
|
|||
class AbsoluteFileField(serializers.FileField): |
|||
def to_representation(self, value): |
|||
if not value: |
|||
return None |
|||
request = self.context.get("request") |
|||
url = value.url if hasattr(value, "url") else str(value) |
|||
if request: |
|||
return request.build_absolute_uri(url) |
|||
return url |
|||
|
|||
|
|||
class AdminPodcastCategorySerializer(serializers.ModelSerializer): |
|||
class Meta: |
|||
model = PodcastCategory |
|||
fields = ["id", "title", "slug", "status", "created_at", "updated_at"] |
|||
|
|||
|
|||
class AdminPodcastCollectionSerializer(serializers.ModelSerializer): |
|||
class Meta: |
|||
model = PodcastCollection |
|||
fields = ["id", "title", "slug", "summary", "display_position", "status", "order", "pin_top"] |
|||
|
|||
|
|||
class AdminPodcastListSerializer(serializers.ModelSerializer): |
|||
thumbnail = AbsoluteImageField(required=False, allow_null=True) |
|||
audio_file = AbsoluteFileField(required=False, allow_null=True) |
|||
categories_detail = AdminPodcastCategorySerializer(source="categories", many=True, read_only=True) |
|||
collections_detail = AdminPodcastCollectionSerializer(source="collections", many=True, read_only=True) |
|||
|
|||
class Meta: |
|||
model = Podcast |
|||
fields = [ |
|||
"id", |
|||
"title", |
|||
"slug", |
|||
"thumbnail", |
|||
"status", |
|||
"view_count", |
|||
"download_count", |
|||
"created_at", |
|||
"updated_at", |
|||
"categories_detail", |
|||
"collections_detail", |
|||
"audio_file" |
|||
] |
|||
read_only_fields = ["id", "view_count", "download_count", "created_at", "updated_at"] |
|||
|
|||
class AdminPodcastDetailSerializer(serializers.ModelSerializer): |
|||
thumbnail = AbsoluteImageField(required=False, allow_null=True) |
|||
audio_file = AbsoluteFileField(required=False, allow_null=True) |
|||
audio_time = serializers.TimeField(required=False) |
|||
categories = serializers.PrimaryKeyRelatedField(queryset=PodcastCategory.objects.all(), many=True, required=False) |
|||
collections = serializers.PrimaryKeyRelatedField(queryset=PodcastCollection.objects.all(), many=True, required=False) |
|||
categories_detail = AdminPodcastCategorySerializer(source="categories", many=True, read_only=True) |
|||
collections_detail = AdminPodcastCollectionSerializer(source="collections", many=True, read_only=True) |
|||
remove_thumbnail = serializers.BooleanField(write_only=True, required=False, default=False) |
|||
remove_audio_file = serializers.BooleanField(write_only=True, required=False, default=False) |
|||
|
|||
class Meta: |
|||
model = Podcast |
|||
fields = [ |
|||
"id", |
|||
"title", |
|||
"slug", |
|||
"thumbnail", |
|||
"description", |
|||
"audio_file", |
|||
"audio_time", |
|||
"status", |
|||
"view_count", |
|||
"download_count", |
|||
"created_at", |
|||
"updated_at", |
|||
"categories", |
|||
"collections", |
|||
"categories_detail", |
|||
"collections_detail", |
|||
"remove_thumbnail", |
|||
"remove_audio_file", |
|||
] |
|||
read_only_fields = ["id", "view_count", "download_count", "created_at", "updated_at"] |
|||
|
|||
def create(self, validated_data): |
|||
validated_data.pop("remove_thumbnail", False) |
|||
validated_data.pop("remove_audio_file", False) |
|||
categories = validated_data.pop("categories", []) |
|||
collections = validated_data.pop("collections", []) |
|||
podcast = super().create(validated_data) |
|||
if categories: |
|||
podcast.categories.set(categories) |
|||
if collections: |
|||
podcast.collections.set(collections) |
|||
return podcast |
|||
|
|||
def update(self, instance, validated_data): |
|||
remove_thumbnail = validated_data.pop("remove_thumbnail", False) |
|||
remove_audio_file = validated_data.pop("remove_audio_file", False) |
|||
categories = validated_data.pop("categories", None) |
|||
collections = validated_data.pop("collections", None) |
|||
|
|||
if remove_thumbnail and instance.thumbnail: |
|||
instance.thumbnail.delete(save=False) |
|||
instance.thumbnail = None |
|||
|
|||
if remove_audio_file and instance.audio_file: |
|||
instance.audio_file.delete(save=False) |
|||
instance.audio_file = None |
|||
|
|||
podcast = super().update(instance, validated_data) |
|||
if categories is not None: |
|||
podcast.categories.set(categories) |
|||
if collections is not None: |
|||
podcast.collections.set(collections) |
|||
return podcast |
|||
@ -0,0 +1,73 @@ |
|||
from django.db.models import Q |
|||
from rest_framework.authentication import TokenAuthentication |
|||
from rest_framework.parsers import FormParser, JSONParser, MultiPartParser |
|||
from rest_framework.permissions import IsAuthenticated |
|||
from rest_framework.viewsets import ModelViewSet, ReadOnlyModelViewSet |
|||
|
|||
from apps.account.permissions import IsSuperAdmin |
|||
from utils.pagination import StandardResultsSetPagination |
|||
|
|||
from .models import Podcast, PodcastCollection, PodcastCategory |
|||
from .serializers_admin import ( |
|||
AdminPodcastCategorySerializer, |
|||
AdminPodcastCollectionSerializer, |
|||
AdminPodcastDetailSerializer, |
|||
AdminPodcastListSerializer, |
|||
) |
|||
|
|||
|
|||
class AdminPodcastCategoryViewSet(ReadOnlyModelViewSet): |
|||
serializer_class = AdminPodcastCategorySerializer |
|||
permission_classes = [IsAuthenticated, IsSuperAdmin] |
|||
authentication_classes = [TokenAuthentication] |
|||
pagination_class = None |
|||
|
|||
def get_queryset(self): |
|||
return PodcastCategory.objects.all().order_by("title") |
|||
|
|||
|
|||
class AdminPodcastCollectionViewSet(ReadOnlyModelViewSet): |
|||
serializer_class = AdminPodcastCollectionSerializer |
|||
permission_classes = [IsAuthenticated, IsSuperAdmin] |
|||
authentication_classes = [TokenAuthentication] |
|||
pagination_class = None |
|||
|
|||
def get_queryset(self): |
|||
return PodcastCollection.objects.all().order_by("display_position", "order", "title") |
|||
|
|||
|
|||
class AdminPodcastViewSet(ModelViewSet): |
|||
permission_classes = [IsAuthenticated, IsSuperAdmin] |
|||
authentication_classes = [TokenAuthentication] |
|||
pagination_class = StandardResultsSetPagination |
|||
parser_classes = (MultiPartParser, FormParser, JSONParser) |
|||
|
|||
def get_serializer_class(self): |
|||
if self.action == "list": |
|||
return AdminPodcastListSerializer |
|||
return AdminPodcastDetailSerializer |
|||
|
|||
def get_queryset(self): |
|||
queryset = Podcast.objects.all().prefetch_related("categories", "collections") |
|||
|
|||
search_query = self.request.query_params.get("search") |
|||
if search_query: |
|||
queryset = queryset.filter( |
|||
Q(title__icontains=search_query) |
|||
| Q(slug__icontains=search_query) |
|||
| Q(description__icontains=search_query) |
|||
) |
|||
|
|||
status_filter = self.request.query_params.get("status") |
|||
if status_filter in {"true", "false"}: |
|||
queryset = queryset.filter(status=status_filter == "true") |
|||
|
|||
category_id = self.request.query_params.get("category") |
|||
if category_id and category_id != "all": |
|||
queryset = queryset.filter(categories__id=category_id) |
|||
|
|||
collection_id = self.request.query_params.get("collection") |
|||
if collection_id and collection_id != "all": |
|||
queryset = queryset.filter(collections__id=collection_id) |
|||
|
|||
return queryset.distinct().order_by("-created_at") |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue