# -*- coding: utf-8 -*- import datetime from django.conf import settings from django.contrib.contenttypes.fields import GenericForeignKey from django.contrib.contenttypes.models import ContentType from django.db import models from redactor.fields import RedactorField from courses.templates import search_in_collection, LEVELS_COLLECTION, MATERIAL_TYPE_COLLECTION, material_fabric, \ comment_fabric from library.models import Tags from lms.settings import DOMAIN from lms.tools import random_string, translit from management.models import Comment from storage.models import Storage import logging MATERIALS_TYPE = ( ('B', u'Базовый материал'), ('E', u'Расширеный материал'), ('P', u'Премиум материал') ) THEME_TYPE = ( MATERIALS_TYPE[0], MATERIALS_TYPE[1], MATERIALS_TYPE[2], ('M', u'Предэкзаменационные материалы'), ('Ex', u'Экзаменационная тема') ) class MaterialDirection(models.Model): title = models.CharField(verbose_name=u'Заголовок', max_length=255) color = models.CharField(verbose_name=u'Цвет', max_length=50) description = RedactorField(verbose_name=u'Описание', blank=True) mentors = models.ManyToManyField(to=settings.AUTH_USER_MODEL, verbose_name=u'Кураторы') def __unicode__(self): return u'%s' % self.title def __str__(self): return self.title def get_face(self): return { 'title': self.title, 'color': self.color, 'description': self.description, 'mentors': [i.get_face() for i in self.mentors.all()] } def get_mentors(self): return self.mentors.all() def html(self): return '{1}'.format(self.color, self.title) def count(self): return Course.objects.filter(direction=self).count() class Meta: verbose_name = u'Направление' verbose_name_plural = u'Направления' class Course(models.Model): COURSE_LEVEL = ( ('B', u'Базовый'), ('A', u'Продвинутый'), ('E', u'Экспертный'), ('B+A', u'Базовый + Продвинутый') ) hidden = models.BooleanField(verbose_name=u'Видно только оплатившим', default=False) level = models.CharField(verbose_name=u'Уровень', choices=COURSE_LEVEL, default='B', max_length=3) slug = models.SlugField(max_length=255, editable=False, blank=True, default='', unique=True) icon = models.ImageField(verbose_name=u'Иконка курса', blank=True, null=True, upload_to='course') direction = models.ForeignKey(MaterialDirection, verbose_name=u'Направление', null=True) mentors = models.ManyToManyField(to=settings.AUTH_USER_MODEL, verbose_name=u'Кураторы', blank=True, related_name='course_mentors') public = models.BooleanField(verbose_name=u'Опубликовать', default=False) title = models.CharField(verbose_name=u"Заголовок", max_length=255) description = RedactorField(verbose_name=u'Описание', blank=True) image = models.ImageField(verbose_name=u'Изображение', upload_to='course', blank=True) big_image = models.ImageField(verbose_name=u'Большое изображение', upload_to='course', blank=True) big_mobile_image = models.ImageField(verbose_name=u'Под мобилку', upload_to='course', blank=True, null=True, help_text=u'Большая картинка для мобильной версии') page = models.URLField(verbose_name=u'Страничка описания', blank=True, default='') preview = models.CharField(verbose_name=u'Трэйл', blank=True, default='', max_length=255) teachers = models.ManyToManyField(to=settings.AUTH_USER_MODEL, verbose_name=u'Преподаватели', related_name='course_teachers') sort = models.IntegerField(verbose_name=u'Порядок сортировки', default=0) use_fail = models.BooleanField(verbose_name=u'Использовать фейковую информацию', default=False) basic_len = models.IntegerField(verbose_name=u'Основных модулей', default=0) addition_len = models.IntegerField(verbose_name=u'Дополнительных модулей', default=0) min_price = models.IntegerField(verbose_name=u'Цена от', default=0) buy_icon = models.ImageField(verbose_name=u'Картинка покупки', upload_to='course', blank=True, null=True) must_build = models.BooleanField(verbose_name=u'На переформировку', default=False) keywords = models.ManyToManyField(Tags, verbose_name=u'Ключевые слова', blank=True) recommend = models.ManyToManyField('self', verbose_name=u'Связанные курсы', blank=True, help_text=u'Курсы, которые стоит порекомендовать вместе с этим') def __str__(self): return self.title def __unicode__(self): return u"%s" % self.title def get_direction(self): return self.direction if self.direction else '' def get_mentors(self): # Получение списка ответственных кураторов result = set() for mentor in self.direction.get_mentors(): result.add(mentor) for mentor in self.mentors.all(): result.add(mentor) return result def get_html_direction(self): return self.direction.html() if self.direction else '' def get_themes(self, t=None): # Получение списка тем в порядке кортежа THEME_TYPE __types = list(i[0] for i in THEME_TYPE) if t in __types: return CourseTheme.objects.filter(course=self, _type=t).order_by('sort') else: result = [] for _type in __types: for i in self.get_themes(t=_type): result.append(i) return result def get_image(self): if self.image: return self.image.url else: return '/static/img/course1.jpg' def get_big_image(self): if self.big_image: return self.big_image.url else: return '/static/img/course1.jpg' def get_mobile_big_image(self): if self.big_mobile_image: return self.big_mobile_image.url else: return self.get_big_image() def get_level(self): # Получить уровень сложности return search_in_collection(LEVELS_COLLECTION, 'flag', self.level) def get_title(self): # Получить заголовок курса return self.title def get_description(self): # Получить описание курса return self.description def get_skills(self): # Получить скилы темы result = [] # Обойти все размеры навыков в for i in SkillJ.objects.filter(lesson__course=self): if i.skill not in result: result.append(i.skill) return result def get_type(self): # Получить тип материала, как по подписке return '' def get_icon(self): # Получить иконку материала, для отображения рядом с курсом return '' def get_materials(self): # Получить прикрепленные файлы, для отображения на странице курса return [] def get_comments(self): # Получить все комментарии return [] def lessons_length(self): return Lesson.objects.filter(course=self).count() def build_map(self, material=None): # Переформирование карты return CourseBuilder(self, material=material).main() def to_build(self): # Отправить на переформирование картыx #self.must_build = True #self.save() self.build_map() def get_absolute_url(self): return '/courses/%s' % self.slug def save(self, *args, **kwargs): if not self.slug: self.slug = '{0}'.format(translit(self.title)) super(Course, self).save(*args, **kwargs) class Meta: verbose_name = u"Курс" verbose_name_plural = u"Курсы" ordering = ['sort'] class CourseTheme(models.Model): on_comment = models.BooleanField(verbose_name=u'Блок комментариев', default=True) teachers = models.ManyToManyField(to=settings.AUTH_USER_MODEL, verbose_name=u'Преподаватели', blank=True) price_type = models.CharField(verbose_name=u'Тип подписки', choices=MATERIALS_TYPE, default='B', max_length=1) _type = models.CharField(verbose_name=u'Тип темы', choices=THEME_TYPE, default='B', max_length=2) icon = models.ImageField(verbose_name=u'Иконка темы', upload_to='CourseTheme', null=True, blank=True) course = models.ForeignKey(Course, verbose_name=u'Курс', null=True) sort = models.IntegerField(verbose_name=u'Текущая сортировка', default=1) title = models.CharField(verbose_name=u'Заголовок', max_length=255, blank=True, default='') description = models.TextField(verbose_name=u'Короткое описание темы', max_length=255, default='', blank=True) empty = models.BooleanField(verbose_name=u'Ты не пройдешь!', help_text=u'Заблокировать дальнейшее прохождение курса. Из-за того, ' u'что курс не заполнен или что-то вроде того.', default=False) def __unicode__(self): return u'%s:%s/%s' % (self.sort, self.course, self.title if self.title else self.get__type_display()) def __str__(self): return u'%s:%s/%s' % (self.sort, self.course, self.title if self.title else self.get__type_display()) def get_lessons(self): return Lesson.objects.filter(theme=self) def get_level(self): # Получить уровень сложности из коллекции, погрузив объект данных в фабрику return search_in_collection(LEVELS_COLLECTION, 'flag', self.course.level) def get_title(self): # Получить заголовок темы if not self.title and Lesson.objects.filter(course=self.course, theme=self).count() != 1: return self.get__type_display() result = u'' if self._type in ['E', 'P', 'M']: result = u'{0}: '.format(self.get__type_display()) if self.title: result += self.title return result else: if Lesson.objects.filter(course=self.course, theme=self).count() == 1: result += Lesson.objects.filter(theme=self).first().get_title() return result def get_description(self): # Получить описание темы result = u'' if self.description: result += u'

%s

' % self.description if self.lessons_length() > 1: result += u'' return result if not self.description and self.lessons_length() == 1: return Lesson.objects.get(theme=self).description if self._type == 'Ex': return Exam.objects.get(theme=self).get_description() def get_skills(self): # Получить скилы темы result = [] # Обойти все размеры навыков в for i in SkillJ.objects.filter(lesson__theme=self): if i.skill not in result: result.append(i.skill) return result def get_type(self): # Получить тип материала/ Здесь идет обход по всем __template = search_in_collection(MATERIAL_TYPE_COLLECTION, 'flag', self._type) __template['icon'] = self.icon if self.icon else __template['icon'] return __template def get_icon(self): # Получить иконку материала if self.icon: return self.icon.url else: return search_in_collection(MATERIAL_TYPE_COLLECTION, 'flag', self._type, artifact='icon') def get_materials(self): # Получить прикрепленные файлы return [] def get_comments(self): # Получить все комментарии return [] def lessons_length(self): return Lesson.objects.filter(theme=self).count() def homework_length(self): return Homework.objects.filter(theme=self).count() def save(self, *args, **kwargs): if CourseTheme.objects.filter(course=self.course, sort=self.sort).exclude(id=self.id).exists(): # Переформировать порядок test_in = self.sort + 1 for theme in CourseTheme.objects.filter(course=self.course, sort__gte=self.sort).exclude(id=self.id): if theme.sort != test_in: theme.sort = test_in theme.save() test_in += 1 if self.course: self.course.to_build() super(CourseTheme, self).save(*args, **kwargs) class Meta: verbose_name = u'Тема' verbose_name_plural = u'Темы' ordering = ['sort'] @property def type(self): return self._type class Lesson(models.Model): COMMENT_SWITCH = ( ('N', 'Включены'), ('F', 'Отключены'), ('T', 'Подчиняется теме') ) free = models.BooleanField(verbose_name=u'Бесплатное видео', default=False) on_comment = models.CharField(verbose_name=u'Блок комментариев', default='T', choices=COMMENT_SWITCH, help_text=u'{0}/management/faq/37'.format(DOMAIN), max_length=1) token = models.CharField(verbose_name=u'Токен доступа', default='', blank=True, max_length=100, editable=False) title = models.TextField(verbose_name=u'Заголовок', blank=True) sort = models.IntegerField(verbose_name=u'Текущая сортировка', default=1) course = models.ForeignKey(Course, verbose_name=u'Курс', null=True) theme = models.ForeignKey(CourseTheme, verbose_name=u'Тема курса', null=True) description = RedactorField(verbose_name=u'Описание', default='', blank=True) video = models.TextField(verbose_name=u'Код видео', default='', blank=True) video_id = models.CharField(verbose_name=u'Видео ID', blank=True, null=True, max_length=50) video_date = models.DateTimeField(verbose_name=u'Время генерации кода видео', blank=True, null=True) materials = models.ManyToManyField(Storage, verbose_name=u'Материалы урока', blank=True) comments = models.ManyToManyField(Comment, verbose_name=u'Комментарии', blank=True, editable=False) def __str__(self): return '%s/%s' % (self.theme, self.title) def __unicode__(self): return u'%s/%s' % (self.theme, self.title) def get_title(self): return self.title def get_description(self): # Просто получить описание этой темы return self.description def get_level(self): # Получить уровень сложности return search_in_collection(LEVELS_COLLECTION, 'flag', self.course.level) def get_skills(self): # Получить скилы темы result = [] # Обойти все размеры навыков в for i in SkillJ.objects.filter(lesson=self): if i.skill not in result: result.append(i.skill) return result def get_type(self): # Получить тип материала return self.theme.get_type() def get_icon(self): # Получить иконку материала return self.theme.get_icon() def get_materials(self): # Получить прикрепленные файлы return material_fabric(self.materials.all()) def get_comments(self, _user=None): # Получить все комментарии урока return [comment_fabric(comment, __type='L', __user=_user) for comment in self.comments.filter(parent_id=0)] def get_all_comments(self, _user=None): return [comment_fabric(comment, __type='L', __user=_user) for comment in self.comments.all().order_by('-date')] def save(self, *args, **kwargs): if not self.video and self.video_id and self.video_id != '0': video = gen_vzaar_bb(self.video_id) if video: self.video = video if Lesson.objects.filter(theme=self.theme, sort=self.sort).exclude(id=self.id).exists(): # Переформировать порядок test_in = self.sort + 1 for lesson in Lesson.objects.filter(theme=self.theme, sort__gte=self.sort).exclude(id=self.id): if lesson.sort != test_in: lesson.sort = test_in lesson.save() test_in += 1 self.token = self.course.build_map(material=self) super(Lesson, self).save(*args, **kwargs) class Meta: verbose_name = u'Урок' verbose_name_plural = u'Уроки' ordering = ['sort'] class Homework(models.Model): token = models.CharField(verbose_name=u'Токен доступа', default='', blank=True, max_length=100) course = models.ForeignKey(Course, verbose_name=u'Курс', null=True) theme = models.ForeignKey(CourseTheme, verbose_name=u'Тема курса', null=True) description = RedactorField(verbose_name=u'Описание') materials = models.ManyToManyField(Storage, verbose_name=u'Материалы для домашней работы', blank=True) sort = models.IntegerField(verbose_name=u'Текущая сортировка', default=1) def __unicode__(self): return u'%s ID: %s Тема: %s Порядок темы: %s' % (self.course.get_title(), self.id, self.theme.title, self.theme.sort) def __str__(self): return '%s ID: %s Тема: %s Порядок темы: %s' % (self.course.get_title(), self.id, self.theme.title, self.theme.sort) def get_skills(self): # Получить скилы темы return [] def get_level(self): # Получить уровень сложности return search_in_collection(LEVELS_COLLECTION, 'flag', self.course.level) def get_type(self): # Получить тип материала return self.theme.get_type() def get_icon(self): # Получить иконку материала return self.theme.get_icon() def get_description(self): # Просто получить описание этой темы return self.description def get_materials(self): # Получить прикрепленные файлы return material_fabric(self.materials.all()) def get_comments(self): # Получить все комментарии return [] def get_title(self): result = self.theme.get_title() if Homework.objects.filter(theme=self.theme).count() > 1: result += ' {0}'.format(self.sort) return result def save(self, *args, **kwargs): if Homework.objects.filter(theme=self.theme, sort=self.sort).exclude(id=self.id).exists(): # Переформировать порядок test_in = self.sort + 1 for homework in Homework.objects.filter(theme=self.theme, sort__gte=self.sort).exclude(id=self.id): if homework.sort != test_in: homework.sort = test_in homework.save() test_in += 1 self.token = self.course.build_map(material=self) super(Homework, self).save(*args, **kwargs) class Meta: verbose_name = u'Добашнее задание' verbose_name_plural = u'Домашние задания' ordering = ['sort'] class Exam(models.Model): token = models.CharField(verbose_name=u'Токен доступа', default='', blank=True, max_length=100) sort = models.IntegerField(verbose_name=u'Порядок экзамена', default=1) course = models.ForeignKey(Course, verbose_name=u'Курс', null=True) theme = models.ForeignKey(CourseTheme, verbose_name=u'Тема курса', null=True) description = RedactorField(verbose_name=u'Описание для студентов') materials = models.ManyToManyField(Storage, verbose_name=u'Материалы экзамена', related_name='exam_materials', blank=True) def __str__(self): return '%s' % self.course def __unicode__(self): return u'%s' % self.course def get_level(self): # Получить уровень сложности return search_in_collection(LEVELS_COLLECTION, 'flag', self.course.level) def get_skills(self): # Получить скилы темы result = [] # Обойти все размеры навыков в for i in SkillJ.objects.filter(lesson__theme=self): if i.skill not in result: result.append(i.skill) return result def get_type(self): # Получить тип материала return self.theme.get_type() def get_icon(self): # Получить иконку материала return self.theme.get_icon() def get_materials(self): # Получить прикрепленные файлы return material_fabric(self.materials.all()) def get_description(self): return self.description def get_comments(self): # Получить все комментарии return [] def get_title(self): return self.theme.get_title() def save(self, *args, **kwargs): if Exam.objects.filter(theme=self.theme, sort=self.sort).exclude(id=self.id).exists(): # Переформировать порядок test_in = self.sort + 1 for exam in Exam.objects.filter(theme=self.theme, sort__gte=self.sort).exclude(id=self.id): if exam.sort != test_in: exam.sort = test_in exam.save() test_in += 1 self.token = self.course.build_map(material=self) super(Exam, self).save(*args, **kwargs) class Meta: verbose_name = u'Экзамен' verbose_name_plural = u'Экзамены' ordering = ['sort'] class Skills(models.Model): title = models.CharField(verbose_name=u'Наименование', max_length=255) color = models.CharField(verbose_name=u'Цвет', max_length=255) mini_icon = models.ImageField(verbose_name=u'Маленькая картинка', upload_to='skills', null=True, help_text='15x15') big_icon = models.ImageField(verbose_name=u'Большая картинка', upload_to='skills', null=True, help_text='65x65') description = models.TextField(verbose_name=u'Описание', blank=True) def __str__(self): return '%s' % self.title def __unicode__(self): return u'%s' % self.title class Meta: verbose_name = u'Навык' verbose_name_plural = u'Навыки' class SkillJ(models.Model): # Журнал навыков skill = models.ForeignKey(Skills, verbose_name=u'Навык') lesson = models.ForeignKey(Lesson, verbose_name=u'Урок') size = models.IntegerField(verbose_name=u'Размер', default=0) def __str__(self): return '%s %s' % (self.skill, self.size) def __unicode__(self): return u'%s %s' % (self.skill, self.size) class Meta: verbose_name = u'Размер навыка' verbose_name_plural = u'Размеры навыков' ordering = ['id'] class Achievements(models.Model): tech_name = models.CharField(verbose_name=u'Техническое название', max_length=20, editable=False, help_text=u'Для системы, нигде не отображается', blank=True, default='', unique=True) icon = models.ImageField(verbose_name=u'Иконка', upload_to='achives') title = models.CharField(verbose_name=u'Имя', max_length=50, help_text=u'Для нашего удобства, студентам не показывается') image = models.ImageField(verbose_name=u'Изображение', upload_to='achives') background = models.CharField(verbose_name=u'Цвет фона', max_length=10) border = models.CharField(verbose_name=u'Цвет границы', max_length=10) def __str__(self): return u'%s' % self.title def __unicode__(self): return u'%s' % self.title def save(self, *args, **kwargs): if not self.tech_name: self.tech_name = random_string().upper() super(Achievements, self).save(*args, **kwargs) class Meta: verbose_name = u'Достижение' verbose_name_plural = u'Достижения' class CourseMap(models.Model): _types = ( ('L', u'Урок'), ('H', u'Домашнее задание'), ('E', u'Экзамен') ) _type = models.CharField(verbose_name=u'Типы материалов', max_length=1, default='L', choices=_types) course = models.ForeignKey(Course, verbose_name=u'Курс', blank=True, null=True) lesson = models.ForeignKey(Lesson, verbose_name=u'Урок', null=True, blank=True) homework = models.ForeignKey(Homework, verbose_name=u'Задание', null=True, blank=True) exam = models.ForeignKey(Exam, verbose_name=u'Экзамен', null=True, blank=True) sort = models.IntegerField(verbose_name=u'Глобальный порядок', default=0) token = models.CharField(verbose_name=u'Быстрый ключ', null=True, editable=False, unique=True, max_length=20) def __unicode__(self): _tmp = None if self._type == 'L': _tmp = self.lesson elif self._type == 'H': _tmp = self.homework elif self._type == 'E': _tmp = self.exam return u'%s %s %s' % (self.token, self.sort, _tmp.get_title()) def __str__(self): _tmp = None if self._type == 'L': _tmp = self.lesson elif self._type == 'H': _tmp = self.homework elif self._type == 'E': _tmp = self.exam return '%s %s %s' % (self.token, self.sort, _tmp.get_title()) def get_type(self): _type = None if self.lesson: _type = 'L' elif self.homework: _type = 'H' elif self.exam: _type = 'E' return _type def get_next(self): try: _next = CourseMap.objects.get(course=self.course, sort=self.sort + 1) except CourseMap.DoesNotExist: _next = CourseMap.objects.get(course=self.course, sort=0) return _next._type, _next.get_obj() def get_before(self): try: _next = CourseMap.objects.get(course=self.course, sort=self.sort - 1) except CourseMap.DoesNotExist: _next = CourseMap.objects.get(course=self.course, sort=0) return _next._type, _next.get_obj() def get_obj(self): if self._type == 'L': return self.lesson elif self._type == 'H': return self.homework elif self._type == 'E': return self.exam else: return None def get_token(self): return '{0}#{1}'.format(self.course.id, self.sort) def check_material(self): result = 0 if self.lesson: result += 1 if self.homework: result += 1 if self.exam: result += 1 return result == 1 def save(self, *args, **kwargs): if not self.course: self.course = self.get_obj().course _token = self.get_token() if _token != self.token: self.token = _token _type = self.get_type() if _type != self._type: self._type = _type super(CourseMap, self).save(*args, **kwargs) class Meta: verbose_name = u'Карта курса' verbose_name_plural = u'Карты курсов' ordering = ['sort'] class AchievementsMap(models.Model): after = models.BooleanField(verbose_name=u'После прохождения', default=True) point = models.ForeignKey(CourseMap, verbose_name=u'Позиция') achiv = models.ForeignKey(Achievements, verbose_name=u'Достижение') def __str__(self): return u'%s %s %s' % (self.point, self.achiv, self.after) def __unicode__(self): return u'%s %s %s' % (self.point, self.achiv, self.after) class Meta: verbose_name = u'Внутреняя ачивка' verbose_name_plural = u'Внетренние ачивки' class Diploma(models.Model): key = models.IntegerField(verbose_name=u'Последний ключ') icon = models.ImageField(verbose_name=u'Мини картинка', upload_to='diploms', null=True) course = models.ForeignKey(Course, verbose_name=u'Курс') out_image = models.ImageField(verbose_name=u'Диплом без печати', upload_to='diploms') in_image = models.ImageField(verbose_name=u'Диплом c печатью', upload_to='diploms') # date_place = models.CharField(verbose_name=u'Размещение даты', max_length=255, help_text=u'Пикселей сверху:пикселей слева - 256:256', null=True) date_color = models.CharField(verbose_name=u'Цвет даты', max_length=255, null=True, help_text=u'RGB. Пример: 0,0,0') date_font = models.FileField(verbose_name=u'Шрифт даты', upload_to='diploms', null=True) date_size = models.IntegerField(verbose_name=u'Размер даты', null=True) # key_place = models.CharField(verbose_name=u'Размещение ключа', max_length=255, null=True, help_text=u'Пикселей сверху:пикселей слева - 256:256') key_color = models.CharField(verbose_name=u'Цвет ключа', max_length=255, null=True, help_text=u'RGB. Пример: 0,0,0') key_font = models.FileField(verbose_name=u'Шрифт ключа', upload_to='diploms', null=True) key_size = models.IntegerField(verbose_name=u'Размер ключа', null=True) # name_place = models.CharField(verbose_name=u'Размещение имени', max_length=255, null=True, help_text=u'Пикселей сверху:пикселей слева - 256:256') name_color = models.CharField(verbose_name=u'Цвет имени', max_length=255, null=True, help_text=u'RGB. Пример: 0,0,0') name_font = models.FileField(verbose_name=u'Шрифт имени', upload_to='diploms', null=True) name_size = models.IntegerField(verbose_name=u'Размер имени', null=True) def __str__(self): return '%s' % self.course def __unicode__(self): return u'%s' % self.course def get_key(self): k = self.key self.key = k + 1 self.save() return k def get_color(self, _type): if _type == 'key': p = self.key_color elif _type == 'name': p = self.name_color elif _type == 'date': p = self.date_color p = p.split(',') return int(p[0]), int(p[1]), int(p[2]) def get_place(self, _type): if _type == 'key': p = self.key_place elif _type == 'name': p = self.name_place elif _type == 'date': p = self.date_place p = p.split(':') return int(p[1]), int(p[0]) class Meta: verbose_name = u'Диплом' verbose_name_plural = u'Дипломы' def gen_vzaar_bb(id): try: int(id) except ValueError: return None if id: return ''.format(id) else: return None class CourseBuilder: def __init__(self, course, material=None): self.course = course self.course_public = self.course.public self.material = material # Вернуть токен вызвавшего материала self.ready = [] self.materials = [] self.token = '' def append_in_price(self, map): # Добавить карту в счета, куда включены все карты курса в типе, исключая текущий #Price.objects.filter(included=map.get_befor) pass def rebuild_map(self): sort = 0 for theme in CourseTheme.objects.filter(course=self.course): for lesson in Lesson.objects.filter(theme=theme): must_save = False try: token = '{0}#{1}'.format(self.course.id, sort) tmp = CourseMap.objects.get(token=token) except CourseMap.DoesNotExist: tmp = CourseMap.objects.create(lesson=lesson, sort=sort, course=self.course) self.append_in_price(tmp) if tmp.homework: tmp.homework = None must_save = True if tmp.exam: tmp.exam = None must_save = True if tmp.lesson != lesson: tmp.lesson = lesson must_save = True if lesson.token != token: lesson.token = token lesson.save() if must_save: tmp.save() if lesson == self.material: self.token = tmp.token self.materials.append(tmp.id) sort += 1 for homework in Homework.objects.filter(theme=theme): must_save = False try: token = '{0}#{1}'.format(self.course.id, sort) tmp = CourseMap.objects.get(token=token) except CourseMap.DoesNotExist: tmp = CourseMap.objects.create(homework=homework, sort=sort, course=self.course) self.append_in_price(tmp) if tmp.homework != homework: tmp.homework = homework must_save = True if tmp.exam: tmp.exam = None must_save = True if tmp.lesson: tmp.lesson = None must_save = True if homework.token != token: homework.token = token homework.save() if must_save: tmp.save() if homework == self.material: self.token = tmp.token self.materials.append(tmp.id) sort += 1 for exam in Exam.objects.filter(theme=theme): must_save = False try: token = '{0}#{1}'.format(self.course.id, sort) tmp = CourseMap.objects.get(token=token) except CourseMap.DoesNotExist: tmp = CourseMap.objects.create(exam=exam, sort=sort, course=self.course) self.append_in_price(tmp) if tmp.exam != exam: tmp.exam = exam must_save = True if tmp.homework: tmp.homework = None must_save = True if tmp.lesson: tmp.lesson = None must_save = True if exam.token != token: exam.token = token exam.save() if must_save: tmp.save() if exam == self.material: self.token = tmp.token self.materials.append(tmp.id) sort += 1 if sort != CourseMap.objects.filter(course=self.course).count(): CourseMap.objects.filter(course=self.course).exclude(id__in=self.materials).delete() def course_switcher(self): # Блокировка курса на время обработки if self.course_public: if self.course.public: self.course.public = False else: self.course.public = True self.course.save() def main(self): self.course_switcher() ## self.rebuild_map() ## self.course_switcher() return self.token if self.material else None # Вернуть токен для материала если он есть # class Flow(models.Model): # title = models.CharField(verbose_name=u'Название', max_length=255) # description = models.TextField( # verbose_name=u'Описание', default='', blank=True, null=True) # course = models.ForeignKey(Course, verbose_name=u'Курс') # start_flow = models.DateTimeField( # verbose_name=u'Дата начала потока', default=datetime.datetime.now) # created = models.DateTimeField( # default=datetime.datetime.now, verbose_name=u"Создан", editable=False) # modified = models.DateTimeField( # auto_now=True, verbose_name=u"Изменен") # # def __str__(self): # return '%s / %s' % (self.title, self.course) # # def __unicode__(self): # return '%s / %s' % (self.title, self.course) # # def get_status(self): # if self.start_flow <= datetime.datetime.now(): # return True # else: # return False # # class Meta: # verbose_name = u'Поток' # verbose_name_plural = u'Потоки' # ordering = ['-modified'] # Модели нового API со временем всё, что выше будет выпилено class Tutorial(models.Model): """ Модель урока. Урок может быть открыт для комментирования и закрыт, по дефолту открыт, вероятно закрывать нужно будет крайне редко. Видео к уроку фрейм который лежит прямо в базе, конечно же костыль и со временем мы уйдём от этого, все видео хостятся на двух онлайн сервисах на клиент нужно передовать id и сервис на котором, это дело хостится, а правило отображения оставить клиенту. Материалы для урока по сути FileField, нужна только для создания лишней связи в таблице и дублирования метазаголовков файла """ on_comment = models.BooleanField(verbose_name=u'Комментарии', default=True) video = models.TextField(verbose_name=u'Код видео', default='', blank=True) materials = models.ManyToManyField(Storage, verbose_name=u'Материалы урока', blank=True) class Task(models.Model): """ Модель таска. Исторически сложилось, что на сервере хостятся два типа тасков отличающихся лишь наименованием домашние работы и экзамены, не нужно быть гением, чтобы понять для чего нужно булево значение is_exam Материалы для урока по сути FileField, нужна только для создания лишней связи в таблице и дублирования метазаголовков файла """ materials = models.ManyToManyField(Storage, verbose_name=u'Материалы для домашней работы', blank=True) is_exam = models.BooleanField(default=False, verbose_name=u'Экзамен или домашка') class Topic(models.Model): """ Модель темы, нужно просто для объединения тасков и уроков. У некоторых тем есть иконка. Возможно поле icon перекачует в Vertex, а данная модель отвалится за ненадобностью """ icon = models.ImageField(verbose_name=u'Иконка темы', upload_to='CourseTheme', null=True, blank=True) class VertexManager(models.Manager): # Менеджер вершин графа. def create_with_dependencies(self, model, course, title, description, materials=None, **kwargs): content_type = ContentType.objects.get(app_label='courses', model=model) obj = content_type.model_class().objects.create(**kwargs) [obj.materials.add(i) for i in materials] if materials else None return self.create( content_type=content_type, object_id=obj.id, course=course, title=title, description=description, ) class Vertex(models.Model): """ Основная структурная единица узел графа курса. Может быть привязана к теме уроку или заданию. Модель создана для минимизации трёх выше указанных. Позволяет работать со структурой курса на более высоком уровне абстракции. """ course = models.ForeignKey(to=Course) title = models.CharField(verbose_name=u'Название', max_length=255) description = models.TextField( verbose_name=u'Описание', default='', blank=True, null=True) children = models.ManyToManyField(to='Vertex', blank=True) content_type = models.ForeignKey(to=ContentType) object_id = models.PositiveIntegerField() content_object = GenericForeignKey('content_type', 'object_id') manager = VertexManager() def __str__(self): return self.title + ': ' + self.get_type() def get_type(self): return self.content_type.__str__() class NormalMap(models.Model): """ Так как курс евляется связным графом мы можем отобразить его бесконечным количеством способов, а нам нужен один самый красивый, мы должный в явном виде указать способ отображения. """ course = models.OneToOneField(to=Course) dependent_elements = models.TextField(default='[]') independent_elements = models.TextField(default='[]')