Merge branch 'feature/api' of gitlab.com:lilcity/backend into feature/create-edit-courses

remotes/origin/hasaccess
Vitaly Baev 8 years ago
commit 06a6c4a8e0
  1. 98
      api/v1/serializers/content.py
  2. 250
      api/v1/serializers/course.py
  3. 2
      api/v1/views.py
  4. 13
      apps/content/admin.py
  5. 19
      apps/content/migrations/0012_auto_20180209_1847.py
  6. 40
      apps/content/migrations/0013_auto_20180212_0537.py
  7. 14
      apps/content/models.py
  8. 19
      apps/course/migrations/0030_auto_20180212_0537.py
  9. 19
      apps/course/models.py
  10. 11
      project/settings.py

@ -13,6 +13,7 @@ class ContentCreateSerializer(serializers.Serializer):
'text',
'image',
'image-text',
'images',
'video',
)
type = serializers.ChoiceField(choices=TYPE_CHOICES)
@ -27,6 +28,8 @@ class ContentCreateSerializer(serializers.Serializer):
return ImageTextSerializer(obj, context=self.context).to_representation(obj)
elif isinstance(obj, Video):
return VideoSerializer(obj, context=self.context).to_representation(obj)
elif isinstance(obj, Gallery):
return GallerySerializer(obj, context=self.context).to_representation(obj)
return super(ContentSerializer, self).to_representation(obj)
@ -52,6 +55,7 @@ class ImageObjectSerializer(serializers.ModelSerializer):
class ImageCreateSerializer(serializers.ModelSerializer):
type = serializers.SerializerMethodField()
class Meta:
model = Image
@ -62,22 +66,28 @@ class ImageCreateSerializer(serializers.ModelSerializer):
'title',
'position',
'img',
'type',
'created_at',
'update_at',
)
read_only_fields = (
'id',
'type',
'created_at',
'update_at',
)
def get_type(self, object):
return 'image'
class ImageSerializer(ImageCreateSerializer):
img = ImageObjectSerializer()
class TextCreateSerializer(serializers.ModelSerializer):
type = serializers.SerializerMethodField()
class Meta:
model = Text
@ -87,22 +97,28 @@ class TextCreateSerializer(serializers.ModelSerializer):
'lesson',
'title',
'position',
'type',
'created_at',
'update_at',
) + ('txt',)
read_only_fields = (
'id',
'type',
'created_at',
'update_at',
)
def get_type(self, object):
return 'text'
class TextSerializer(TextCreateSerializer):
pass
class ImageTextCreateSerializer(serializers.ModelSerializer):
type = serializers.SerializerMethodField()
class Meta:
model = ImageText
@ -114,22 +130,28 @@ class ImageTextCreateSerializer(serializers.ModelSerializer):
'position',
'img',
'txt',
'type',
'created_at',
'update_at',
)
read_only_fields = (
'id',
'type',
'created_at',
'update_at',
)
def get_type(self, object):
return 'image-text'
class ImageTextSerializer(ImageTextCreateSerializer):
img = ImageObjectSerializer()
class VideoCreateSerializer(serializers.ModelSerializer):
type = serializers.SerializerMethodField()
class Meta:
model = Video
@ -139,83 +161,101 @@ class VideoCreateSerializer(serializers.ModelSerializer):
'lesson',
'title',
'position',
'type',
'created_at',
'update_at',
) + ('url',)
read_only_fields = (
'id',
'type',
'created_at',
'update_at',
)
def get_type(self, object):
return 'video'
class VideoSerializer(VideoCreateSerializer):
pass
class ContentSerializer(serializers.ModelSerializer):
class GalleryImageCreateSerializer(serializers.ModelSerializer):
class Meta:
model = Content
model = GalleryImage
fields = (
'id',
'course',
'lesson',
'title',
'position',
'gallery',
'img',
'created_at',
'update_at',
)
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)
read_only_fields = (
'id',
'created_at',
'update_at',
)
class GalleryImageSerializer(GalleryImageCreateSerializer):
img = ImageObjectSerializer()
class GallerySerializer(serializers.ModelSerializer):
type = serializers.SerializerMethodField()
gallery_images = GalleryImageSerializer(many=True)
class Meta:
model = Gallery
fields = (
'id',
'course',
'lesson',
'title',
'position',
'gallery_images',
'type',
'created_at',
'update_at',
)
read_only_fields = (
'id',
'type',
'created_at',
'update_at',
)
def get_type(self, object):
return 'images'
class GalleryImageCreateSerializer(serializers.ModelSerializer):
class ContentSerializer(serializers.ModelSerializer):
class Meta:
model = GalleryImage
model = Content
fields = (
'id',
'gallery',
'img',
'created_at',
'update_at',
)
read_only_fields = (
'id',
'course',
'lesson',
'title',
'position',
'created_at',
'update_at',
)
class GalleryImageSerializer(GalleryImageCreateSerializer):
img = ImageObjectSerializer()
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)
elif isinstance(obj, Gallery):
return GallerySerializer(obj, context=self.context).to_representation(obj)
return super(ContentSerializer, self).to_representation(obj)

@ -76,6 +76,7 @@ class CourseCreateSerializer(serializers.ModelSerializer):
required=False,
)
materials = MaterialSerializer(many=True, required=False)
gallery = GallerySerializer()
class Meta:
model = Course
@ -110,12 +111,7 @@ class CourseCreateSerializer(serializers.ModelSerializer):
'update_at',
)
def create(self, validated_data):
materials = validated_data.pop('materials', [])
content = validated_data.pop('content', [])
course = super().create(validated_data)
def dispatch_content(self, course, content, materials):
for c in content:
if c['type'] == 'text':
if 'id' in c['data'] and c['data']['id']:
@ -134,14 +130,14 @@ class CourseCreateSerializer(serializers.ModelSerializer):
)
elif c['type'] == 'image':
if 'id' in c['data'] and c['data']['id']:
i = Image.objects.get(id=c['data']['id'])
i.position = c['data']['position']
i.title = c['data']['title']
i.course = course
i.img = ImageObject.objects.get(id=c['data']['img'])
i.save()
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:
i = Image.objects.create(
image = Image.objects.create(
position=c['data']['position'],
title=c['data']['title'],
course=course,
@ -179,56 +175,156 @@ class CourseCreateSerializer(serializers.ModelSerializer):
course=course,
url=c['data']['url'],
)
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()
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']
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['id'])
)
else:
m = Material.objects.create(
title=material['title'],
cover=ImageObject.objects.get(id=material['cover']),
short_description=material['short_description'],
g = Gallery.objects.create(
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['id']),
)
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.course = course
g.position = 0
g.save()
else:
g = Gallery.objects.create(
title=gallery.get('title', ''),
course=course,
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_gallery(course, gallery)
return course
def update(self, instance, validated_data):
materials = validated_data.pop('materials', [])
content = validated_data.pop('content', [])
materials = validated_data.pop('materials', [])
gallery = validated_data.pop('gallery', {})
course = super().update(instance, validated_data)
self.dispatch_content(course, content, materials)
self.dispatch_gallery(course, gallery)
return course
class CourseSerializer(CourseCreateSerializer):
category = CategorySerializer()
materials = MaterialSerializer(many=True)
cover = ImageObjectSerializer()
gallery = GallerySerializer()
content = ContentSerializer(many=True)
class LessonCreateSerializer(serializers.ModelSerializer):
content = serializers.ListSerializer(
child=ContentCreateSerializer(),
required=False,
)
class Meta:
model = Lesson
fields = (
'id',
'title',
'short_description',
'course',
'cover',
'content',
'created_at',
'update_at',
)
read_only_fields = (
'id',
'created_at',
'update_at',
)
def dispatch_content(self, lesson, validated_data, 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']
t.course = course
t.lesson = lesson
t.txt = c['data']['txt']
t.save()
else:
t = Text.objects.create(
position=c['data']['position'],
title=c['data']['title'],
course=course,
lesson=lesson,
txt=c['data']['txt'],
)
elif c['type'] == 'image':
if 'id' in c['data'] and c['data']['id']:
i = Image.objects.get(id=c['data']['id'])
i.position = c['data']['position']
i.title = c['data']['title']
i.course = course
i.img = ImageObject.objects.get(id=c['data']['img'])
i.save()
image = Image.objects.get(id=c['data']['id'])
image.position = c['data']['position']
image.title = c['data']['title']
image.lesson = lesson
image.img = ImageObject.objects.get(id=c['data']['img'])
image.save()
else:
i = Image.objects.create(
image = Image.objects.create(
position=c['data']['position'],
title=c['data']['title'],
course=course,
lesson=lesson,
img=ImageObject.objects.get(id=c['data']['img']),
)
elif c['type'] == 'image-text':
@ -236,7 +332,7 @@ class CourseCreateSerializer(serializers.ModelSerializer):
it = ImageText.objects.get(id=c['data']['id'])
it.position = c['data']['position']
it.title = c['data']['title']
it.course = course
it.lesson = lesson
it.img = ImageObject.objects.get(id=c['data']['img'])
it.txt = c['data']['txt']
it.save()
@ -244,7 +340,7 @@ class CourseCreateSerializer(serializers.ModelSerializer):
it = ImageText.objects.create(
position=c['data']['position'],
title=c['data']['title'],
course=course,
lesson=lesson,
img=ImageObject.objects.get(id=c['data']['img']),
txt=c['data']['txt'],
)
@ -253,64 +349,54 @@ class CourseCreateSerializer(serializers.ModelSerializer):
v = Video.objects.get(id=c['data']['id'])
v.position = c['data']['position']
v.title = c['data']['title']
v.course = course
v.lesson = lesson
v.url = c['data']['url']
v.save()
else:
v = Video.objects.create(
position=c['data']['position'],
title=c['data']['title'],
course=course,
lesson=lesson,
url=c['data']['url'],
)
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()
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']
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['id']),
)
else:
m = Material.objects.create(
title=material['title'],
cover=ImageObject.objects.get(id=material['cover']),
short_description=material['short_description'],
g = Gallery.objects.create(
position=c['data']['position'],
title=c['data']['title'],
)
course.materials.add(m)
return course
class CourseSerializer(CourseCreateSerializer):
category = CategorySerializer()
materials = MaterialSerializer(many=True)
cover = ImageObjectSerializer()
gallery = GallerySerializer()
content = ContentSerializer(many=True)
if 'images' in c['data']:
for image in c['data']['images']:
gi = GalleryImage.objects.create(
gallery=g,
img=ImageObject.objects.get(id=image['id']),
)
class LessonCreateSerializer(serializers.ModelSerializer):
class Meta:
model = Lesson
fields = (
'id',
'title',
'short_description',
'course',
'cover',
'content',
'created_at',
'update_at',
)
def create(self, validated_data):
content = validated_data.pop('content', [])
lesson = super().create(validated_data)
self.dispatch_content(lesson, validated_data, content)
return lesson
read_only_fields = (
'id',
'content',
'created_at',
'update_at',
)
def update(self, instance, validated_data):
content = validated_data.pop('content', [])
lesson = super().update(instance, validated_data)
self.dispatch_content(lesson, validated_data, content)
return lesson
class LessonSerializer(LessonCreateSerializer):
course = CourseSerializer()
cover = ImageObjectSerializer()
content = ContentSerializer()

@ -73,7 +73,7 @@ class CategoryViewSet(ExtendedModelViewSet):
class CourseViewSet(ExtendedModelViewSet):
queryset = Course.objects.select_related(
'author', 'category', 'cover',
'author', 'category', 'cover', 'gallery',
).prefetch_related(
'likes', 'materials', 'content',
).all()

@ -48,6 +48,11 @@ class VideoAdmin(ContentChildAdmin):
base_model = Video
@admin.register(Gallery)
class GalleryAdmin(ContentChildAdmin):
base_model = Gallery
@admin.register(Content)
class ContentAdmin(PolymorphicParentModelAdmin):
base_model = Content
@ -55,15 +60,11 @@ class ContentAdmin(PolymorphicParentModelAdmin):
Image,
Text,
ImageText,
Video
Video,
GalleryAdmin,
)
@admin.register(Gallery)
class GalleryAdmin(admin.ModelAdmin):
pass
@admin.register(GalleryImage)
class GalleryImageAdmin(admin.ModelAdmin):
pass

@ -0,0 +1,19 @@
# Generated by Django 2.0.2 on 2018-02-09 18:47
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('content', '0011_auto_20180209_1549'),
]
operations = [
migrations.AlterField(
model_name='galleryimage',
name='gallery',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='gallery_images', to='content.Gallery', verbose_name='Галерея'),
),
]

@ -0,0 +1,40 @@
# Generated by Django 2.0.2 on 2018-02-12 05:37
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('content', '0012_auto_20180209_1847'),
]
operations = [
migrations.AlterModelOptions(
name='gallery',
options={'base_manager_name': 'objects'},
),
migrations.RemoveField(
model_name='gallery',
name='created_at',
),
migrations.RemoveField(
model_name='gallery',
name='id',
),
migrations.RemoveField(
model_name='gallery',
name='title',
),
migrations.RemoveField(
model_name='gallery',
name='update_at',
),
migrations.AddField(
model_name='gallery',
name='content_ptr',
field=models.OneToOneField(auto_created=True, default=1, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='content.Content'),
preserve_default=False,
),
]

@ -66,22 +66,14 @@ class Video(Content):
url = models.URLField('Ссылка')
class Gallery(models.Model):
title = models.CharField('Заголовок', max_length=100, default='')
created_at = models.DateTimeField(auto_now_add=True)
update_at = models.DateTimeField(auto_now=True)
class Meta:
verbose_name = 'Галерея'
verbose_name_plural = 'Галереи'
ordering = ('-created_at',)
class Gallery(Content):
pass
class GalleryImage(models.Model):
gallery = models.ForeignKey(
Gallery, on_delete=models.CASCADE,
verbose_name='Галерея'
verbose_name='Галерея', related_name='gallery_images'
)
img = models.ForeignKey(
ImageObject, related_name='gallery_images',

@ -0,0 +1,19 @@
# Generated by Django 2.0.2 on 2018-02-12 05:37
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('course', '0029_auto_20180209_0911'),
]
operations = [
migrations.AlterField(
model_name='course',
name='gallery',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='results_gallery', to='content.Gallery', verbose_name='Галерея работ'),
),
]

@ -42,9 +42,11 @@ class Course(models.Model):
User, on_delete=models.SET_NULL, null=True, blank=True)
title = models.CharField('Название курса', max_length=100, db_index=True)
short_description = models.TextField(
'Краткое описание курса', db_index=True)
'Краткое описание курса', db_index=True
)
from_author = models.TextField(
'От автора', default='', null=True, blank=True)
'От автора', default='', null=True, blank=True
)
cover = models.ForeignKey(
ImageObject, related_name='course_covers',
verbose_name='Обложка курса', on_delete=models.CASCADE,
@ -63,12 +65,14 @@ class Course(models.Model):
duration = models.IntegerField('Продолжительность курса', default=0)
is_featured = models.BooleanField(default=False)
status = models.PositiveSmallIntegerField(
'Статус', default=0, choices=STATUS_CHOICES)
'Статус', default=0, choices=STATUS_CHOICES
)
likes = models.ManyToManyField(Like, blank=True)
materials = models.ManyToManyField('Material', blank=True)
gallery = models.ForeignKey(
Gallery, verbose_name='Галерея работ',
on_delete=models.CASCADE, null=True, blank=True,
related_name='results_gallery',
)
created_at = models.DateTimeField(auto_now_add=True)
@ -141,7 +145,8 @@ class Lesson(models.Model):
title = models.CharField('Название урока', max_length=100)
short_description = models.TextField('Краткое описание урока')
course = models.ForeignKey(
Course, on_delete=models.CASCADE, related_name='lessons')
Course, on_delete=models.CASCADE, related_name='lessons'
)
cover = models.ForeignKey(
ImageObject, related_name='lesson_covers',
verbose_name='Обложка урока', on_delete=models.CASCADE,
@ -207,7 +212,8 @@ class Comment(PolymorphicMPTTModel):
class CourseComment(Comment):
course = models.ForeignKey(
Course, on_delete=models.CASCADE, related_name='comments')
Course, on_delete=models.CASCADE, related_name='comments'
)
class Meta(Comment.Meta):
verbose_name = 'Комментарий курса'
@ -216,7 +222,8 @@ class CourseComment(Comment):
class LessonComment(Comment):
lesson = models.ForeignKey(
Lesson, on_delete=models.CASCADE, related_name='comments')
Lesson, on_delete=models.CASCADE, related_name='comments'
)
class Meta(Comment.Meta):
verbose_name = 'Комментарий урока'

@ -186,13 +186,16 @@ ACTIVE_LINK_STRICT = True
# DRF settings
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.TokenAuthentication',
'rest_framework.authentication.SessionAuthentication',
],
'DEFAULT_PERMISSION_CLASSES': [
),
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.AllowAny',
],
),
'DEFAULT_RENDERER_CLASSES': (
'rest_framework.renderers.JSONRenderer',
),
'DEFAULT_FILTER_BACKENDS': (
'django_filters.rest_framework.DjangoFilterBackend',
'rest_framework.filters.SearchFilter',

Loading…
Cancel
Save