diff --git a/publications/admin.py b/publications/admin.py index 8fb973b..2f7ad35 100644 --- a/publications/admin.py +++ b/publications/admin.py @@ -1,9 +1,9 @@ from django.contrib import admin -from .models import Publication, Rating +from .models import Publication, Rating, Category # Register your models here. class PublicationAdmin(admin.ModelAdmin): - list_display = ('pk', 'content_type', 'is_pinned', 'user', 'time_created', 'time_updated') + list_display = ('pk', 'content_type', 'category', 'is_pinned', 'user', 'time_created', 'time_updated') list_display_links = ('pk', 'content_type') list_filter = ('content_type', 'is_pinned') readonly_fields = ('time_created', 'time_updated') @@ -16,4 +16,5 @@ class RatingAdmin(admin.ModelAdmin): search_fields = ('user__username', ) admin.site.register(Publication, PublicationAdmin) -admin.site.register(Rating, RatingAdmin) \ No newline at end of file +admin.site.register(Rating, RatingAdmin) +admin.site.register(Category) \ No newline at end of file diff --git a/publications/managers.py b/publications/managers.py index de85fa0..3f1061b 100644 --- a/publications/managers.py +++ b/publications/managers.py @@ -1,5 +1,6 @@ from typing import TypeVar from django.db.models import Avg +from django.db.models.functions import Coalesce from django.db import models T = TypeVar('T') @@ -7,7 +8,7 @@ T = TypeVar('T') class PublicationQuerySet(models.QuerySet[T]): def with_score(self): qs = self - qs = qs.annotate(average_score=Avg("ratings__score")) + qs = qs.annotate(average_score=Coalesce(Avg("ratings__score"), 0.0)) return qs def only_publish(self): diff --git a/publications/models.py b/publications/models.py index 28ff923..1ebf30c 100644 --- a/publications/models.py +++ b/publications/models.py @@ -47,10 +47,6 @@ class Publication(models.Model): def __str__(self): return f'Content #{self.pk}' - - @property - def average_score(self) -> int: - return getattr(self, "average_score", None) def clean(self): errors = [] diff --git a/publications/serializers.py b/publications/serializers.py index 3f28fbb..050d044 100644 --- a/publications/serializers.py +++ b/publications/serializers.py @@ -12,7 +12,31 @@ class CategorySerializer(serializers.ModelSerializer): class PublicationSerializer(serializers.ModelSerializer): category_detail = CategorySerializer(source="category", read_only=True) user_detail = PublicUserSerializer(source="user", read_only=True) - average_score = serializers.IntegerField(read_only=True) + average_score = serializers.SerializerMethodField(read_only=True) + + def get_average_score(self, obj): + return getattr(obj, 'average_score', 0) + + def validate(self, attrs): + content_type = attrs.get('content_type') + image = attrs.get('image') + video = attrs.get('video') + + errors = {} + + if content_type == 'image' and not image: + errors['image'] = 'Required image file' + + if content_type == 'video' and not video: + errors['video'] = 'Required video file' + + if image and video: + errors['non_field_errors'] = 'You must upload either a video or an image, not both' + + if errors: + raise serializers.ValidationError(errors) + + return attrs class Meta: model = Publication diff --git a/publications/views.py b/publications/views.py index 99d1ed4..22d60de 100644 --- a/publications/views.py +++ b/publications/views.py @@ -39,6 +39,9 @@ class PublicationsAPIView(ListCreateAPIView): return [IsAuthenticated()] return super().get_permissions() + + def perform_create(self, serializer: PublicationSerializer): + serializer.save(user=self.request.user) @extend_schema( tags=['Publications'], @@ -66,6 +69,9 @@ class AdminPublicationsAPIView(PublicationsAPIView): def get_permissions(self): return [IsProfessorOnly()] + + def perform_create(self, serializer: AdminPublicationSerializer): + serializer.save(user=self.request.user) @extend_schema( tags=['Publications'], @@ -92,10 +98,11 @@ class CategoryListAPIView(ListCreateAPIView): filter_backends = [filters.SearchFilter, filters.OrderingFilter] ordering = ['name'] search_fields = ['name'] + pagination_class = None def get_permissions(self): if self.request.method == 'POST': - return [IsAdminUser] + return [IsAdminUser()] return super().get_permissions() @extend_schema( diff --git a/users/views.py b/users/views.py index 3b1b9fa..8658e64 100644 --- a/users/views.py +++ b/users/views.py @@ -5,7 +5,7 @@ from rest_framework.request import Request from rest_framework.response import Response from rest_framework import status from rest_framework.views import APIView -from rest_framework.generics import RetrieveUpdateDestroyAPIView, ListAPIView, RetrieveAPIView +from rest_framework.generics import RetrieveUpdateDestroyAPIView, ListAPIView, RetrieveAPIView, ListCreateAPIView from rest_framework.permissions import IsAuthenticated, IsAdminUser from rest_framework.authtoken.models import Token @@ -87,9 +87,17 @@ class UserAPIView(RetrieveUpdateDestroyAPIView): serializer_class = UserForAdminSerializer permission_classes = [IsAdminUser] -@extend_schema(tags=['Users'], - summary='List of all available school ids (only admin)') -class SchoolListAPIView(ListAPIView): +@extend_schema( + tags=['Users'], + methods=['GET'], + summary='List school ids', +) +@extend_schema( + tags=['Users'], + methods=['POST'], + summary='Create new school id (only admin)', +) +class SchoolListAPIView(ListCreateAPIView): queryset = SchoolID.objects.all() serializer_class = SchoolIDSerializer permission_classes = [IsAdminUser]