diff --git a/api/v1/serializers/course.py b/api/v1/serializers/course.py index c8be42e9..54ccc44c 100644 --- a/api/v1/serializers/course.py +++ b/api/v1/serializers/course.py @@ -13,7 +13,7 @@ from apps.course.models import ( from .content import ( ImageObjectSerializer, ContentSerializer, ContentCreateSerializer, GallerySerializer, ) -from .mixins import DispatchContentMixin, DispatchGalleryMixin, DispatchMaterialMixin +from .mixins import DispatchContentMixin, DispatchGalleryMixin, DispatchMaterialMixin, DispatchTagsMixin from .user import UserSerializer User = get_user_model() @@ -22,7 +22,7 @@ User = get_user_model() class TagSerializer(serializers.ModelSerializer): class Meta: model = Tag - fields = ('tag',) + fields = ('__all__') class MaterialCreateSerializer(serializers.ModelSerializer): @@ -109,6 +109,7 @@ class CourseBulkChangeCategorySerializer(serializers.Serializer): class CourseCreateSerializer(DispatchContentMixin, DispatchGalleryMixin, DispatchMaterialMixin, + DispatchTagsMixin, serializers.ModelSerializer ): title = serializers.CharField(allow_blank=True) @@ -169,12 +170,14 @@ class CourseCreateSerializer(DispatchContentMixin, materials = validated_data.pop('materials', []) gallery = validated_data.pop('gallery', {}) author = validated_data.get('author', None) + tags = validated_data.pop('tags', []) if not author: validated_data['author'] = self.context['request'].user course = super().create(validated_data) self.dispatch_content(course, content) self.dispatch_materials(course, materials) self.dispatch_gallery(course, gallery) + self.dispatch_tags(course, tags) return course def update(self, instance, validated_data): @@ -182,12 +185,14 @@ class CourseCreateSerializer(DispatchContentMixin, materials = validated_data.pop('materials', []) gallery = validated_data.pop('gallery', {}) author = validated_data.get('author', None) + tags = validated_data.pop('tags', []) if not instance.author or author and instance.author != author: validated_data['author'] = self.context['request'].user course = super().update(instance, validated_data) self.dispatch_materials(course, materials) self.dispatch_content(course, content) self.dispatch_gallery(course, gallery) + self.dispatch_tags(course, tags) return course def to_representation(self, instance): diff --git a/api/v1/serializers/mixins.py b/api/v1/serializers/mixins.py index 451b362a..d488a1c8 100644 --- a/api/v1/serializers/mixins.py +++ b/api/v1/serializers/mixins.py @@ -1,4 +1,4 @@ -from apps.course.models import Category, Course, Material, Lesson, Like +from apps.course.models import Category, Course, Material, Lesson, Like, Tag, CourseTags from apps.school.models import LiveLesson from apps.content.models import ( @@ -163,3 +163,30 @@ class DispatchGalleryMixin(object): ) obj.gallery = g obj.save() + + +class DispatchTagsMixin(object): + + def dispatch_tags(self, obj, tags): + current_tags = list(obj.tags.all()) + new_tags = [] + if tags: + for tag in tags: + id = tag.get('id') + tag_text = tag.get('tag') + if not id and tag_text: + t, created = Tag.objects.get_or_create(tag=tag_text) + id = t.id + new_tags.append(id) + if isinstance(obj, Course): + CourseTags.objects.filter(course=obj, tag__in=current_tags).delete() + for tag in Tag.objects.filter(id__in=new_tags): + CourseTags.objects.get_or_create(course=obj, tag=tag) + else: + obj.tags.clear(current_tags) + obj.tags.add(Tag.objects.filter(id__in=set(new_tags))) + for tag in current_tags: + if not tag.course_set.all().count(): + tag.delete() + + diff --git a/api/v1/views.py b/api/v1/views.py index 6123f9e2..fdfb5a12 100644 --- a/api/v1/views.py +++ b/api/v1/views.py @@ -779,3 +779,8 @@ class TagViewSet(ExtendedModelViewSet): queryset = Tag.objects.all() serializer_class = TagSerializer search_fields = ('tag',) + + def list(self, request, *args, **kwargs): + queryset = self.filter_queryset(self.get_queryset()) + serializer = self.get_serializer(queryset, many=True) + return Response(serializer.data) diff --git a/apps/course/migrations/0050_auto_20190815_1537.py b/apps/course/migrations/0050_auto_20190818_1043.py similarity index 85% rename from apps/course/migrations/0050_auto_20190815_1537.py rename to apps/course/migrations/0050_auto_20190818_1043.py index 9cab27c1..d6635716 100644 --- a/apps/course/migrations/0050_auto_20190815_1537.py +++ b/apps/course/migrations/0050_auto_20190818_1043.py @@ -1,4 +1,4 @@ -# Generated by Django 2.0.7 on 2019-08-15 15:37 +# Generated by Django 2.0.7 on 2019-08-18 10:43 from django.db import migrations, models import django.db.models.deletion @@ -15,7 +15,7 @@ class Migration(migrations.Migration): name='CourseTags', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('course_id', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='course.Course')), + ('course', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='course.Course')), ], ), migrations.CreateModel( @@ -27,7 +27,7 @@ class Migration(migrations.Migration): ), migrations.AddField( model_name='coursetags', - name='tag_id', + name='tag', field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='course.Tag'), ), migrations.AddField( diff --git a/apps/course/models.py b/apps/course/models.py index bf1383be..ad520377 100644 --- a/apps/course/models.py +++ b/apps/course/models.py @@ -45,8 +45,8 @@ class Tag(models.Model): class CourseTags(models.Model): - tag_id = models.ForeignKey(Tag, on_delete=models.CASCADE) - course_id = models.ForeignKey('Course', on_delete=models.CASCADE) + tag = models.ForeignKey(Tag, on_delete=models.CASCADE) + course = models.ForeignKey('Course', on_delete=models.CASCADE) class Course(BaseModel, DeactivatedMixin): diff --git a/apps/course/templates/course/courses.html b/apps/course/templates/course/courses.html index 45f3f749..6b96b327 100644 --- a/apps/course/templates/course/courses.html +++ b/apps/course/templates/course/courses.html @@ -32,7 +32,8 @@
{% for tag in tags %} - #{{ tag.tag }} + #{{ tag.tag }} {% endfor %}
{% endif %} diff --git a/apps/course/views.py b/apps/course/views.py index 65a5f2c1..5da37691 100644 --- a/apps/course/views.py +++ b/apps/course/views.py @@ -317,11 +317,11 @@ class CoursesView(ListView): q = self.request.GET.get('q') if q: if q.startswith('#'): - queryset = queryset.filter(tags__tag__istartswith=q[1:]) + queryset = queryset.filter(tags__tag__istartswith=q[1:]).distinct() else: queryset = queryset.filter(Q(tags__tag__icontains=q) | Q(title__icontains=q) | Q(short_description__icontains=q) | Q(author__first_name__icontains=q) | Q(author__last_name__icontains=q) - | Q(author__email__icontains=q)) + | Q(author__email__icontains=q)).distinct() filtered = CourseFilter(self.request.GET, queryset=queryset) return filtered.qs @@ -335,10 +335,8 @@ class CoursesView(ListView): group by {ct.tag_id} order by count(*) desc limit 15''', ct=CourseTags) - tags = Tag.objects.filter(id__in=execute_sql(sql)).order_by('tag') - print('tags', tags) - context['tags'] = map(lambda i: i[0], sorted(tags, key=lambda i: len(i[1]))[:15]) - print("context['tags']", context['tags']) + tags = [t[0] for t in execute_sql(sql)] + context['tags'] = Tag.objects.filter(id__in=tags).order_by('tag') context['search_query'] = self.request.GET.get('q', '') context['banners'] = Banner.get_for_page(Banner.PAGE_COURSES) context['course_items'] = Course.shuffle(context.get('course_items')) diff --git a/web/src/components/CourseRedactor.vue b/web/src/components/CourseRedactor.vue index 655c70db..e529f12d 100644 --- a/web/src/components/CourseRedactor.vue +++ b/web/src/components/CourseRedactor.vue @@ -119,7 +119,8 @@ placeholder="Выберите возраст"/> -