diff --git a/api/v1/serializers/course.py b/api/v1/serializers/course.py index dfa14245..833dd98a 100644 --- a/api/v1/serializers/course.py +++ b/api/v1/serializers/course.py @@ -12,6 +12,8 @@ from apps.content.models import ( Gallery, GalleryImage, ImageObject, ) +from .mixins import DispatchContentMixin, DispatchGalleryMixin, DispatchMaterialMixin + class MaterialCreateSerializer(serializers.ModelSerializer): @@ -69,7 +71,11 @@ class CategorySerializer(serializers.ModelSerializer): ) -class CourseCreateSerializer(serializers.ModelSerializer): +class CourseCreateSerializer(DispatchContentMixin, + DispatchGalleryMixin, + DispatchMaterialMixin, + serializers.ModelSerializer + ): slug = serializers.SlugField(allow_unicode=True, required=False) content = serializers.ListSerializer( child=ContentCreateSerializer(), @@ -100,6 +106,7 @@ class CourseCreateSerializer(serializers.ModelSerializer): 'materials', 'created_at', 'update_at', + 'deactivated_at', 'content', 'gallery', ) @@ -109,146 +116,16 @@ class CourseCreateSerializer(serializers.ModelSerializer): 'url', 'created_at', 'update_at', + 'deactivated_at', ) - def dispatch_content(self, course, content, materials): - for c in content: - if c['type'] == 'text': - if 'id' in c['data'] and c['data']['id']: - t = Text.objects.get(id=c['data']['id']) - t.position = c['data']['position'] - t.title = c['data']['title'] - t.course = course - t.txt = c['data']['txt'] - t.save() - else: - t = Text.objects.create( - position=c['data']['position'], - title=c['data']['title'], - course=course, - txt=c['data']['txt'], - ) - elif c['type'] == 'image': - if 'id' in c['data'] and c['data']['id']: - image = Image.objects.get(id=c['data']['id']) - image.position = c['data']['position'] - image.title = c['data']['title'] - image.course = course - image.img = ImageObject.objects.get(id=c['data']['img']) - image.save() - else: - image = Image.objects.create( - position=c['data']['position'], - title=c['data']['title'], - course=course, - img=ImageObject.objects.get(id=c['data']['img']), - ) - elif c['type'] == 'image-text': - if 'id' in c['data'] and c['data']['id']: - it = ImageText.objects.get(id=c['data']['id']) - it.position = c['data']['position'] - it.title = c['data']['title'] - it.course = course - it.img = ImageObject.objects.get(id=c['data']['img']) - it.txt = c['data']['txt'] - it.save() - else: - it = ImageText.objects.create( - position=c['data']['position'], - title=c['data']['title'], - course=course, - img=ImageObject.objects.get(id=c['data']['img']), - txt=c['data']['txt'], - ) - elif c['type'] == 'video': - if 'id' in c['data'] and c['data']['id']: - v = Video.objects.get(id=c['data']['id']) - v.position = c['data']['position'] - v.title = c['data']['title'] - v.course = course - v.url = c['data']['url'] - v.save() - else: - v = Video.objects.create( - position=c['data']['position'], - title=c['data']['title'], - course=course, - url=c['data']['url'], - ) - elif c['type'] == 'images': - if 'id' in c['data'] and c['data']['id']: - g = Gallery.objects.get(id=c['data']['id']) - g.course = course - g.position = c['data']['position'] - g.title = c['data']['title'] - g.save() - if 'images' in c['data']: - for image in c['data']['images']: - gi = GalleryImage.objects.create( - gallery=g, - img=ImageObject.objects.get(id=image['img']) - ) - else: - g = Gallery.objects.create( - course=course, - position=c['data']['position'], - title=c['data']['title'], - ) - if 'images' in c['data']: - for image in c['data']['images']: - gi = GalleryImage.objects.create( - gallery=g, - img=ImageObject.objects.get(id=image['img']), - ) - - for material in materials: - if 'id' in material and material['id']: - m = Material.objects.get(id=material['id']) - m.title = material['title'] - m.cover = ImageObject.objects.get(id=material['cover']) - m.short_description = material['short_description'] - m.save() - else: - m = Material.objects.create( - title=material['title'], - cover=ImageObject.objects.get(id=material['cover']), - short_description=material['short_description'], - ) - course.materials.add(m) - - def dispatch_gallery(self, course, gallery): - if gallery: - if 'id' in gallery and gallery['id']: - g = Gallery.objects.get(id=gallery['id']) - g.title = gallery.get('title', g.title) - g.position = 0 - g.save() - else: - g = Gallery.objects.create( - title=gallery.get('title', ''), - position=0, - ) - if 'images' in gallery: - for image in gallery['images']: - if 'id' in image and image['id']: - gi = GalleryImage.objects.get(id=image['id']) - gi.gallery = g - gi.img = image['img'] - gi.save() - else: - gi = GalleryImage.objects.create( - gallery=g, - img=image['img'], - ) - course.gallery = g - course.save() - def create(self, validated_data): content = validated_data.pop('content', []) materials = validated_data.pop('materials', []) gallery = validated_data.pop('gallery', {}) course = super().create(validated_data) - self.dispatch_content(course, content, materials) + self.dispatch_content(course, content) + self.dispatch_materials(course, materials) self.dispatch_gallery(course, gallery) return course @@ -257,10 +134,14 @@ class CourseCreateSerializer(serializers.ModelSerializer): materials = validated_data.pop('materials', []) gallery = validated_data.pop('gallery', {}) course = super().update(instance, validated_data) + self.dispatch_materials(course, materials) self.dispatch_content(course, content, materials) self.dispatch_gallery(course, gallery) return course + def to_representation(self, instance): + return CourseSerializer(instance, context=self.context).to_representation(instance) + class CourseSerializer(CourseCreateSerializer): category = CategorySerializer() @@ -287,87 +168,93 @@ class LessonCreateSerializer(serializers.ModelSerializer): 'content', 'created_at', 'update_at', + 'deactivated_at', ) read_only_fields = ( 'id', 'created_at', 'update_at', + 'deactivated_at', ) - def dispatch_content(self, lesson, validated_data, content): + def dispatch_content(self, lesson, content): for c in content: - if c['type'] == 'text': - if 'id' in c['data'] and c['data']['id']: - t = Text.objects.get(id=c['data']['id']) - t.position = c['data']['position'] - t.title = c['data']['title'] + if 'type' not in c or not c['type'] or 'data' not in c or not c['data']: + continue + ctype = c['type'] + cdata = c['data'] + if ctype == 'text': + if 'id' in cdata and cdata['id']: + t = Text.objects.get(id=cdata['id']) + t.position = cdata['position'] + t.title = cdata['title'] t.lesson = lesson - t.txt = c['data']['txt'] + t.txt = cdata['txt'] t.save() else: t = Text.objects.create( - position=c['data']['position'], - title=c['data']['title'], + position=cdata['position'], + title=cdata['title'], lesson=lesson, - txt=c['data']['txt'], + txt=cdata['txt'], ) - elif c['type'] == 'image': - if 'id' in c['data'] and c['data']['id']: - image = Image.objects.get(id=c['data']['id']) - image.position = c['data']['position'] - image.title = c['data']['title'] + elif ctype == 'image': + if 'id' in cdata and cdata['id']: + image = Image.objects.get(id=cdata['id']) + image.position = cdata['position'] + image.title = cdata['title'] image.lesson = lesson - image.img = ImageObject.objects.get(id=c['data']['img']) + image.img = ImageObject.objects.get(id=cdata['img']) image.save() else: image = Image.objects.create( - position=c['data']['position'], - title=c['data']['title'], + position=cdata['position'], + title=cdata['title'], lesson=lesson, - img=ImageObject.objects.get(id=c['data']['img']), + img=ImageObject.objects.get(id=cdata['img']), ) - elif c['type'] == 'image-text': - if 'id' in c['data'] and c['data']['id']: - it = ImageText.objects.get(id=c['data']['id']) - it.position = c['data']['position'] - it.title = c['data']['title'] + elif ctype == 'image-text': + if 'id' in cdata and cdata['id']: + it = ImageText.objects.get(id=cdata['id']) + it.position = cdata['position'] + it.title = cdata['title'] it.lesson = lesson - it.img = ImageObject.objects.get(id=c['data']['img']) - it.txt = c['data']['txt'] + it.img = ImageObject.objects.get(id=cdata['img']) + it.txt = cdata['txt'] it.save() else: it = ImageText.objects.create( - position=c['data']['position'], - title=c['data']['title'], + position=cdata['position'], + title=cdata['title'], lesson=lesson, - img=ImageObject.objects.get(id=c['data']['img']), - txt=c['data']['txt'], + img=ImageObject.objects.get(id=cdata['img']), + txt=cdata['txt'], ) - elif c['type'] == 'video': - if 'id' in c['data'] and c['data']['id']: - v = Video.objects.get(id=c['data']['id']) - v.position = c['data']['position'] - v.title = c['data']['title'] + elif ctype == 'video': + if 'id' in cdata and cdata['id']: + v = Video.objects.get(id=cdata['id']) + v.position = cdata['position'] + v.title = cdata['title'] v.lesson = lesson - v.url = c['data']['url'] + v.url = cdata['url'] v.save() else: v = Video.objects.create( - position=c['data']['position'], - title=c['data']['title'], + position=cdata['position'], + title=cdata['title'], lesson=lesson, - url=c['data']['url'], + url=cdata['url'], ) - elif c['type'] == 'images': - if 'id' in c['data'] and c['data']['id']: - g = Gallery.objects.get(id=c['data']['id']) - g.position = c['data']['position'] - g.title = c['data']['title'] + elif ctype == 'images': + if 'id' in cdata and cdata['id']: + g = Gallery.objects.get(id=cdata['id']) + g.position = cdata['position'] + g.title = cdata['title'] g.lesson = lesson g.save() - if 'images' in c['data']: - for image in c['data']['images']: + if 'images' in cdata: + for image in cdata['images']: gi = GalleryImage.objects.create( gallery=g, img=ImageObject.objects.get(id=image['img']), @@ -375,11 +262,11 @@ class LessonCreateSerializer(serializers.ModelSerializer): else: g = Gallery.objects.create( lesson=lesson, - position=c['data']['position'], - title=c['data']['title'], + position=cdata['position'], + title=cdata['title'], ) - if 'images' in c['data']: - for image in c['data']['images']: + if 'images' in cdata: + for image in cdata['images']: gi = GalleryImage.objects.create( gallery=g, img=ImageObject.objects.get(id=image['img']), @@ -388,17 +275,17 @@ class LessonCreateSerializer(serializers.ModelSerializer): def create(self, validated_data): content = validated_data.pop('content', []) lesson = super().create(validated_data) - self.dispatch_content(lesson, validated_data, content) + self.dispatch_content(lesson, content) return lesson def update(self, instance, validated_data): content = validated_data.pop('content', []) lesson = super().update(instance, validated_data) - self.dispatch_content(lesson, validated_data, content) + self.dispatch_content(lesson, content) return lesson class LessonSerializer(LessonCreateSerializer): course = CourseSerializer() cover = ImageObjectSerializer() - content = ContentSerializer() + content = ContentSerializer(many=True) diff --git a/api/v1/serializers/mixins.py b/api/v1/serializers/mixins.py new file mode 100644 index 00000000..e709002e --- /dev/null +++ b/api/v1/serializers/mixins.py @@ -0,0 +1,152 @@ +from apps.course.models import Category, Course, Material, Lesson, Like + +from apps.content.models import ( + Content, Image, Text, ImageText, Video, + Gallery, GalleryImage, ImageObject, +) + + +class DispatchContentMixin(object): + + def dispatch_content(self, course, content): + for c in content: + if 'type' not in c or not c['type'] or 'data' not in c or not c['data']: + continue + ctype = c['type'] + cdata = c['data'] + if ctype == 'text': + if 'id' in cdata and cdata['id']: + t = Text.objects.get(id=cdata['id']) + t.position = cdata['position'] + t.title = cdata['title'] + t.course = course + t.txt = cdata['txt'] + t.save() + else: + t = Text.objects.create( + position=cdata['position'], + title=cdata['title'], + course=course, + txt=cdata['txt'], + ) + elif ctype == 'image': + if 'id' in cdata and cdata['id']: + image = Image.objects.get(id=cdata['id']) + image.position = cdata['position'] + image.title = cdata['title'] + image.course = course + image.img = ImageObject.objects.get(id=cdata['img']) + image.save() + else: + image = Image.objects.create( + position=cdata['position'], + title=cdata['title'], + course=course, + img=ImageObject.objects.get(id=cdata['img']), + ) + elif ctype == 'image-text': + if 'id' in cdata and cdata['id']: + it = ImageText.objects.get(id=cdata['id']) + it.position = cdata['position'] + it.title = cdata['title'] + it.course = course + it.img = ImageObject.objects.get(id=cdata['img']) + it.txt = cdata['txt'] + it.save() + else: + it = ImageText.objects.create( + position=cdata['position'], + title=cdata['title'], + course=course, + img=ImageObject.objects.get(id=cdata['img']), + txt=cdata['txt'], + ) + elif ctype == 'video': + if 'id' in cdata and cdata['id']: + v = Video.objects.get(id=cdata['id']) + v.position = cdata['position'] + v.title = cdata['title'] + v.course = course + v.url = cdata['url'] + v.save() + else: + v = Video.objects.create( + position=cdata['position'], + title=cdata['title'], + course=course, + url=cdata['url'], + ) + elif ctype == 'images': + if 'id' in cdata and cdata['id']: + g = Gallery.objects.get(id=cdata['id']) + g.course = course + g.position = cdata['position'] + g.title = cdata['title'] + g.save() + if 'images' in cdata: + for image in cdata['images']: + gi = GalleryImage.objects.create( + gallery=g, + img=ImageObject.objects.get(id=image['img']) + ) + else: + g = Gallery.objects.create( + course=course, + position=cdata['position'], + title=cdata['title'], + ) + if 'images' in cdata: + for image in cdata['images']: + gi = GalleryImage.objects.create( + gallery=g, + img=ImageObject.objects.get(id=image['img']), + ) + + +class DispatchMaterialMixin(object): + + def dispatch_materials(self, course, materials): + for material in materials: + if 'id' in material and material['id']: + m = Material.objects.get(id=material['id']) + m.title = material['title'] + m.cover = ImageObject.objects.get(id=material['cover']) + m.short_description = material['short_description'] + m.save() + else: + m = Material.objects.create( + title=material['title'], + cover=ImageObject.objects.get(id=material['cover']), + short_description=material['short_description'], + ) + course.materials.add(m) + + +class DispatchGalleryMixin(object): + + def dispatch_gallery(self, course, gallery): + if gallery: + if 'id' in gallery and gallery['id']: + g = Gallery.objects.get(id=gallery['id']) + g.title = gallery.get('title', g.title) + g.position = 0 + g.save() + else: + g = Gallery.objects.create( + title=gallery.get('title', ''), + position=0, + ) + if 'images' in gallery: + for image in gallery['images']: + if 'id' in image and image['id']: + gi = GalleryImage.objects.get(id=image['id']) + gi.gallery = g + gi.img = image['img'] + gi.save() + else: + gi = GalleryImage.objects.create( + gallery=g, + img=image['img'], + ) + course.gallery = g + course.save() diff --git a/apps/content/admin.py b/apps/content/admin.py index 34b19204..555ba173 100644 --- a/apps/content/admin.py +++ b/apps/content/admin.py @@ -23,6 +23,7 @@ class ImageObjectAdmin(admin.ModelAdmin): class ContentChildAdmin(PolymorphicChildModelAdmin): base_model = Content + show_in_index = True base_fieldsets = ( (None, {'fields': ('course', 'lesson', 'title', 'position',)}), ) @@ -56,12 +57,13 @@ class GalleryAdmin(ContentChildAdmin): @admin.register(Content) class ContentAdmin(PolymorphicParentModelAdmin): base_model = Content + polymorphic_list = True child_models = ( Image, Text, ImageText, Video, - GalleryAdmin, + # GalleryAdmin, ) diff --git a/apps/content/models.py b/apps/content/models.py index 6f0932bc..00c15312 100644 --- a/apps/content/models.py +++ b/apps/content/models.py @@ -40,7 +40,10 @@ class Content(PolymorphicModel): class Meta: verbose_name = 'Контент' verbose_name_plural = 'Контент' - ordering = ('-created_at',) + ordering = ('position', '-created_at',) + + def ctype(self): + return self.__class__.__name__.lower() class Image(Content): @@ -65,6 +68,9 @@ class ImageText(Content): class Video(Content): url = models.URLField('Ссылка') + def video_index(self): + return self.url.split('/')[-1] + class Gallery(Content): pass diff --git a/apps/course/migrations/0031_auto_20180213_0906.py b/apps/course/migrations/0031_auto_20180213_0906.py new file mode 100644 index 00000000..e0880533 --- /dev/null +++ b/apps/course/migrations/0031_auto_20180213_0906.py @@ -0,0 +1,23 @@ +# Generated by Django 2.0.2 on 2018-02-13 09:06 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('course', '0030_auto_20180212_0537'), + ] + + operations = [ + migrations.AddField( + model_name='course', + name='deactivated_at', + field=models.DateTimeField(blank=True, default=None, null=True), + ), + migrations.AddField( + model_name='lesson', + name='deactivated_at', + field=models.DateTimeField(blank=True, default=None, null=True), + ), + ] diff --git a/apps/course/models.py b/apps/course/models.py index 0eb620cb..b0a2045d 100644 --- a/apps/course/models.py +++ b/apps/course/models.py @@ -7,6 +7,8 @@ from django.contrib.auth import get_user_model from django.urls import reverse_lazy from polymorphic_tree.models import PolymorphicMPTTModel, PolymorphicTreeForeignKey +from project.mixins import BaseModel, DeactivatedMixin + from .manager import CategoryQuerySet from apps.content.models import ImageObject, Gallery @@ -25,7 +27,7 @@ def default_slug(): return str(uuid4()) -class Course(models.Model): +class Course(BaseModel, DeactivatedMixin): PENDING = 0 PUBLISHED = 1 ARCHIVED = 2 @@ -141,7 +143,7 @@ class Category(models.Model): ordering = ['title'] -class Lesson(models.Model): +class Lesson(BaseModel, DeactivatedMixin): title = models.CharField('Название урока', max_length=100) short_description = models.TextField('Краткое описание урока') course = models.ForeignKey( diff --git a/apps/course/templates/course/content/gallery.html b/apps/course/templates/course/content/gallery.html new file mode 100644 index 00000000..771df8b6 --- /dev/null +++ b/apps/course/templates/course/content/gallery.html @@ -0,0 +1,19 @@ +{% if results %} +
-
-
-
-
-
-
-
-
-
-
-
-