From ac3f21ad6d81b95c4192dd9df7cbf8106dcc948b Mon Sep 17 00:00:00 2001 From: Ivlev Denis Date: Fri, 9 Feb 2018 11:04:53 +0300 Subject: [PATCH 1/2] Splitting serializers by own files --- api/v1/__init__.py | 26 +- api/v1/serializers/__init__.py | 25 ++ api/v1/serializers/content.py | 217 ++++++++++++++++ .../{serializers.py => serializers/course.py} | 245 +----------------- api/v1/serializers/user.py | 53 ++++ api/v1/views.py | 12 +- apps/content/admin.py | 3 + 7 files changed, 315 insertions(+), 266 deletions(-) create mode 100644 api/v1/serializers/__init__.py create mode 100644 api/v1/serializers/content.py rename api/v1/{serializers.py => serializers/course.py} (66%) create mode 100644 api/v1/serializers/user.py diff --git a/api/v1/__init__.py b/api/v1/__init__.py index 8c95c2f2..01a1d18d 100644 --- a/api/v1/__init__.py +++ b/api/v1/__init__.py @@ -5,7 +5,7 @@ import uuid from django.core.files.base import ContentFile -from rest_framework import serializers, viewsets +from rest_framework import viewsets from rest_framework.response import Response # https://gist.github.com/ivlevdenis/a0c8f5b472b6b8550bbb016c6a30e0be @@ -48,27 +48,3 @@ class ExtendViewSet(object): class ExtendedModelViewSet(ExtendViewSet, viewsets.ModelViewSet): pass - - -class Base64ImageField(serializers.ImageField): - - def to_internal_value(self, data): - if isinstance(data, six.string_types): - if 'data:' in data and ';base64,' in data: - header, data = data.split(';base64,') - try: - decoded_file = base64.b64decode(data) - except TypeError: - self.fail('invalid_image') - - file_name = str(uuid.uuid4())[:12] - file_extension = self.get_file_extension( - file_name, decoded_file) - complete_file_name = "%s.%s" % (file_name, file_extension,) - data = ContentFile(decoded_file, name=complete_file_name) - return super().to_internal_value(data) - - def get_file_extension(self, file_name, decoded_file): - extension = imghdr.what(file_name, decoded_file) - extension = "jpg" if extension == "jpeg" else extension - return extension diff --git a/api/v1/serializers/__init__.py b/api/v1/serializers/__init__.py new file mode 100644 index 00000000..42dcdc7c --- /dev/null +++ b/api/v1/serializers/__init__.py @@ -0,0 +1,25 @@ +from rest_framework import serializers + + +class Base64ImageField(serializers.ImageField): + + def to_internal_value(self, data): + if isinstance(data, six.string_types): + if 'data:' in data and ';base64,' in data: + header, data = data.split(';base64,') + try: + decoded_file = base64.b64decode(data) + except TypeError: + self.fail('invalid_image') + + file_name = str(uuid.uuid4())[:12] + file_extension = self.get_file_extension( + file_name, decoded_file) + complete_file_name = "%s.%s" % (file_name, file_extension,) + data = ContentFile(decoded_file, name=complete_file_name) + return super().to_internal_value(data) + + def get_file_extension(self, file_name, decoded_file): + extension = imghdr.what(file_name, decoded_file) + extension = "jpg" if extension == "jpeg" else extension + return extension diff --git a/api/v1/serializers/content.py b/api/v1/serializers/content.py new file mode 100644 index 00000000..73b32225 --- /dev/null +++ b/api/v1/serializers/content.py @@ -0,0 +1,217 @@ +import imghdr +import base64 +import six +import uuid + +from django.core.files.base import ContentFile + +from rest_framework import serializers + +from apps.content.models import ( + Content, Image, Text, ImageText, Video, + Gallery, GalleryImage, ImageObject, +) + +from . import Base64ImageField +# from .course import CourseSerializer + + +class ContentCreateSerializer(serializers.Serializer): + TYPE_CHOICES = ( + 'text', + 'image', + 'imagetext', + 'video', + ) + type = serializers.ChoiceField(choices=TYPE_CHOICES) + data = serializers.JSONField() + + +class ImageObjectSerializer(serializers.ModelSerializer): + image = Base64ImageField( + required=True, allow_empty_file=False, allow_null=False, read_only=False, + ) + + class Meta: + model = ImageObject + fields = ( + 'id', + 'image', + 'created_at', + 'update_at', + ) + + read_only_fields = ( + 'id', + 'created_at', + 'update_at', + ) + + +class ImageCreateSerializer(serializers.ModelSerializer): + + class Meta: + model = Image + fields = ( + 'id', + 'course', + 'lesson', + 'title', + 'position', + 'img', + 'created_at', + 'update_at', + ) + + read_only_fields = ( + 'id', + 'created_at', + 'update_at', + ) + + +class ImageSerializer(ImageCreateSerializer): + # course = CourseSerializer() + # lesson = LessonSerializer() + img = ImageObjectSerializer() + + +class TextCreateSerializer(serializers.ModelSerializer): + + class Meta: + model = Text + fields = ( + 'id', + 'course', + 'lesson', + 'title', + 'position', + 'created_at', + 'update_at', + ) + ('txt',) + + read_only_fields = ( + 'id', + 'created_at', + 'update_at', + ) + + +class TextSerializer(TextCreateSerializer): + pass + # course = CourseSerializer() + # lesson = LessonSerializer() + + +class ImageTextCreateSerializer(serializers.ModelSerializer): + + class Meta: + model = ImageText + fields = ( + 'id', + 'course', + 'lesson', + 'title', + 'position', + 'img', + 'txt', + 'created_at', + 'update_at', + ) + + read_only_fields = ( + 'id', + 'created_at', + 'update_at', + ) + + +class ImageTextSerializer(ImageTextCreateSerializer): + # course = CourseSerializer() + # lesson = LessonSerializer() + img = ImageObjectSerializer() + + +class VideoCreateSerializer(serializers.ModelSerializer): + + class Meta: + model = Video + fields = ( + 'id', + 'course', + 'lesson', + 'title', + 'position', + 'created_at', + 'update_at', + ) + ('url',) + + read_only_fields = ( + 'id', + 'created_at', + 'update_at', + ) + + +class VideoSerializer(VideoCreateSerializer): + pass + # course = CourseSerializer() + # lesson = LessonSerializer() + + +class ContentSerializer(serializers.ModelSerializer): + + class Meta: + model = Content + + def to_representation(self, obj): + if isinstance(obj, Image): + return ImageSerializer(obj, context=self.context).to_representation(obj) + elif isinstance(obj, Text): + return TextSerializer(obj, context=self.context).to_representation(obj) + elif isinstance(obj, ImageText): + return ImageTextSerializer(obj, context=self.context).to_representation(obj) + elif isinstance(obj, Video): + return VideoSerializer(obj, context=self.context).to_representation(obj) + return super(ContentSerializer, self).to_representation(obj) + + +class GallerySerializer(serializers.ModelSerializer): + + class Meta: + model = Gallery + fields = ( + 'id', + 'title', + 'created_at', + 'update_at', + ) + + read_only_fields = ( + 'id', + 'created_at', + 'update_at', + ) + + +class GalleryImageCreateSerializer(serializers.ModelSerializer): + + class Meta: + model = GalleryImage + fields = ( + 'id', + 'gallery', + 'img', + 'created_at', + 'update_at', + ) + + read_only_fields = ( + 'id', + 'created_at', + 'update_at', + ) + + +class GalleryImageSerializer(GalleryImageCreateSerializer): + img = ImageObjectSerializer() diff --git a/api/v1/serializers.py b/api/v1/serializers/course.py similarity index 66% rename from api/v1/serializers.py rename to api/v1/serializers/course.py index 0c39f59e..d75e3a13 100644 --- a/api/v1/serializers.py +++ b/api/v1/serializers/course.py @@ -1,77 +1,11 @@ -from django.contrib.auth import get_user_model from rest_framework import serializers -from . import Base64ImageField - from apps.course.models import Category, Course, Material, Lesson, Like -from apps.content.models import ( - Image, Text, ImageText, Video, - Gallery, GalleryImage, ImageObject, -) - -User = get_user_model() - - -class ImageObjectSerializer(serializers.ModelSerializer): - image = Base64ImageField( - required=True, allow_empty_file=False, allow_null=False, read_only=False, - ) - - class Meta: - model = ImageObject - fields = ( - 'id', - 'image', - 'created_at', - 'update_at', - ) - - read_only_fields = ( - 'id', - 'created_at', - 'update_at', - ) - -class GallerySerializer(serializers.ModelSerializer): - - class Meta: - model = Gallery - fields = ( - 'id', - 'title', - 'created_at', - 'update_at', - ) - - read_only_fields = ( - 'id', - 'created_at', - 'update_at', - ) - - -class GalleryImageCreateSerializer(serializers.ModelSerializer): - - class Meta: - model = GalleryImage - fields = ( - 'id', - 'gallery', - 'img', - 'created_at', - 'update_at', - ) - - read_only_fields = ( - 'id', - 'created_at', - 'update_at', - ) - - -class GalleryImageSerializer(GalleryImageCreateSerializer): - img = ImageObjectSerializer() +from .content import ( + ImageObjectSerializer, ContentSerializer, ContentCreateSerializer, + GallerySerializer, GalleryImageSerializer, +) class MaterialCreateSerializer(serializers.ModelSerializer): @@ -130,19 +64,8 @@ class CategorySerializer(serializers.ModelSerializer): ) -class ContentSerializer(serializers.Serializer): - TYPE_CHOICES = ( - 'text', - 'image', - 'imagetext', - 'video', - ) - type = serializers.ChoiceField(choices=TYPE_CHOICES) - data = serializers.JSONField() - - class CourseCreateSerializer(serializers.ModelSerializer): - content = serializers.ListSerializer(child=ContentSerializer()) + content = serializers.ListSerializer(child=ContentCreateSerializer()) materials = MaterialSerializer(many=True) class Meta: @@ -214,7 +137,7 @@ class CourseCreateSerializer(serializers.ModelSerializer): course=course, img=Image.objects.get(c['data']['img']), ) - elif c['type'] == 'imagetext': + elif c['type'] == 'image-text': if 'id' in c['data']: it = ImageText.objects.get(id=c['data']['id']) it.position = c['data']['position'] @@ -352,6 +275,7 @@ class CourseSerializer(CourseCreateSerializer): materials = MaterialSerializer(many=True) cover = ImageObjectSerializer() gallery = GallerySerializer() + content = ContentSerializer(many=True) class LessonCreateSerializer(serializers.ModelSerializer): @@ -380,158 +304,3 @@ class LessonCreateSerializer(serializers.ModelSerializer): class LessonSerializer(LessonCreateSerializer): course = CourseSerializer() cover = ImageObjectSerializer() - - -class ImageCreateSerializer(serializers.ModelSerializer): - - class Meta: - model = Image - fields = ( - 'id', - 'course', - 'lesson', - 'title', - 'position', - 'img', - 'created_at', - 'update_at', - ) - - read_only_fields = ( - 'id', - 'created_at', - 'update_at', - ) - - -class ImageSerializer(ImageCreateSerializer): - course = CourseSerializer() - lesson = LessonSerializer() - img = ImageObjectSerializer() - - -class TextCreateSerializer(serializers.ModelSerializer): - - class Meta: - model = Text - fields = ( - 'id', - 'course', - 'lesson', - 'title', - 'position', - 'created_at', - 'update_at', - ) + ('txt',) - - read_only_fields = ( - 'id', - 'created_at', - 'update_at', - ) - - -class TextSerializer(TextCreateSerializer): - course = CourseSerializer() - lesson = LessonSerializer() - - -class ImageTextCreateSerializer(serializers.ModelSerializer): - - class Meta: - model = ImageText - fields = ( - 'id', - 'course', - 'lesson', - 'title', - 'position', - 'img', - 'txt', - 'created_at', - 'update_at', - ) - - read_only_fields = ( - 'id', - 'created_at', - 'update_at', - ) - - -class ImageTextSerializer(ImageTextCreateSerializer): - course = CourseSerializer() - lesson = LessonSerializer() - img = ImageObjectSerializer() - - -class VideoCreateSerializer(serializers.ModelSerializer): - - class Meta: - model = Video - fields = ( - 'id', - 'course', - 'lesson', - 'title', - 'position', - 'created_at', - 'update_at', - ) + ('url',) - - read_only_fields = ( - 'id', - 'created_at', - 'update_at', - ) - - -class VideoSerializer(VideoCreateSerializer): - course = CourseSerializer() - lesson = LessonSerializer() - - -class UserSerializer(serializers.ModelSerializer): - - class Meta: - model = User - fields = ( - 'id', - 'username', - 'email', - 'first_name', - 'last_name', - 'is_staff', - 'is_active', - 'date_joined', - 'role', - 'gender', - 'country', - 'city', - 'about', - 'instagram', - 'facebook', - 'twitter', - 'pinterest', - 'youtube', - 'vkontakte', - 'fb_id', - 'fb_data', - 'is_email_proved', - 'photo', - ) - - read_only_fields = ( - 'id', - 'photo', - 'date_joined', - 'is_staff', - 'fb_id', - 'fb_data', - ) - - -class UserPhotoSerializer(serializers.Serializer): - photo = Base64ImageField( - required=False, allow_empty_file=True, allow_null=True - ) diff --git a/api/v1/serializers/user.py b/api/v1/serializers/user.py new file mode 100644 index 00000000..bd5ac93b --- /dev/null +++ b/api/v1/serializers/user.py @@ -0,0 +1,53 @@ +from django.contrib.auth import get_user_model +from rest_framework import serializers + +from . import Base64ImageField + + +User = get_user_model() + + +class UserSerializer(serializers.ModelSerializer): + + class Meta: + model = User + fields = ( + 'id', + 'username', + 'email', + 'first_name', + 'last_name', + 'is_staff', + 'is_active', + 'date_joined', + 'role', + 'gender', + 'country', + 'city', + 'about', + 'instagram', + 'facebook', + 'twitter', + 'pinterest', + 'youtube', + 'vkontakte', + 'fb_id', + 'fb_data', + 'is_email_proved', + 'photo', + ) + + read_only_fields = ( + 'id', + 'photo', + 'date_joined', + 'is_staff', + 'fb_id', + 'fb_data', + ) + + +class UserPhotoSerializer(serializers.Serializer): + photo = Base64ImageField( + required=False, allow_empty_file=True, allow_null=True + ) diff --git a/api/v1/views.py b/api/v1/views.py index db87e030..e934d32a 100644 --- a/api/v1/views.py +++ b/api/v1/views.py @@ -6,20 +6,26 @@ from rest_framework.decorators import detail_route, list_route from rest_framework.response import Response from . import ExtendedModelViewSet -from .serializers import ( + +from .serializers.course import ( CategorySerializer, LikeSerializer, CourseSerializer, CourseCreateSerializer, MaterialSerializer, MaterialCreateSerializer, + LessonSerializer, LessonCreateSerializer, +) +from .serializers.content import ( ImageSerializer, ImageCreateSerializer, TextSerializer, TextCreateSerializer, ImageTextSerializer, ImageTextCreateSerializer, VideoSerializer, VideoCreateSerializer, GallerySerializer, GalleryImageSerializer, GalleryImageCreateSerializer, - UserSerializer, UserPhotoSerializer, - LessonSerializer, LessonCreateSerializer, ImageObjectSerializer, ) +from .serializers.user import ( + UserSerializer, UserPhotoSerializer, +) + from .permissions import IsAdmin, IsAdminOrIsSelf, IsAuthorOrAdmin, IsAuthorObjectOrAdmin from apps.course.models import Category, Course, Material, Lesson, Like diff --git a/apps/content/admin.py b/apps/content/admin.py index bb935e08..c30a3a38 100644 --- a/apps/content/admin.py +++ b/apps/content/admin.py @@ -23,6 +23,9 @@ class ImageObjectAdmin(admin.ModelAdmin): class ContentChildAdmin(PolymorphicChildModelAdmin): base_model = Content + base_fieldsets = ( + (None, {'fields': ('course', 'lesson', 'title', 'position',)}), + ) @admin.register(Image) From ce2ed4a70bee6b121c3d2dee1733a5073146593d Mon Sep 17 00:00:00 2001 From: Ivlev Denis Date: Fri, 9 Feb 2018 11:05:29 +0300 Subject: [PATCH 2/2] Remove not needed imports --- api/v1/__init__.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/api/v1/__init__.py b/api/v1/__init__.py index 01a1d18d..45967a33 100644 --- a/api/v1/__init__.py +++ b/api/v1/__init__.py @@ -1,9 +1,4 @@ -import imghdr -import base64 -import six -import uuid -from django.core.files.base import ContentFile from rest_framework import viewsets from rest_framework.response import Response