@ -91,6 +91,7 @@ class Course(models.Model):
help_text = ' Большая картинка для мобильной версии ' , max_length = 255 )
teachers = models . ManyToManyField ( to = settings . AUTH_USER_MODEL , verbose_name = ' Преподаватели ' ,
related_name = ' course_teachers ' )
route = models . OneToOneField ( to = " CourseRoute " , verbose_name = " Порядок прохождения по умолчанию " , blank = True , null = True )
def __str__ ( self ) :
return self . title
@ -144,7 +145,7 @@ class Course(models.Model):
if i not in [ ' topic ' , ' tutorial ' , ' task ' ] :
raise ValueError ( ' undefined model: ' + i )
vertex = Vertex . objects . get ( id = self . coursemap . get_first ( ) )
vertex = Vertex . objects . get ( id = self . coursemap_set . get ( sort = 0 ) . get_first ( ) )
if vertex . content_type . model in vertex_model_list :
return vertex
@ -160,7 +161,7 @@ class Course(models.Model):
if i not in [ ' topic ' , ' tutorial ' , ' task ' ] :
raise ValueError ( ' undefined model: ' + i )
vertex = Vertex . objects . get ( id = self . coursemap . get_last ( ) )
vertex = Vertex . objects . get ( id = self . coursemap_set . get ( sort = 0 ) . get_last ( ) )
if vertex . content_type . model in vertex_model_list :
return vertex
@ -334,9 +335,6 @@ class Vertex(models.Model):
if not user . is_authenticated :
return False
if self . extraprivilege_set . filter ( user = user ) . exists ( ) :
return True
try :
progress = self . course . progress_set . get ( user = user )
except ObjectDoesNotExist :
@ -388,58 +386,80 @@ class Task(models.Model):
Материалы для урока по сути FileField , нужна только для создания лишней связи в таблице
и дублирования метазаголовков файла
"""
materials = models . ManyToManyField ( Storage , verbose_name = u ' Материалы для домашней работы ' , blank = True )
is_exam = models . BooleanField ( default = False , verbose_name = u ' Экзамен или домашка ' )
materials = models . ManyToManyField ( Storage , verbose_name = ' Материалы для домашней работы ' , blank = True )
is_exam = models . BooleanField ( default = False , verbose_name = ' Экзамен или домашка ' )
class Topic ( models . Model ) :
"""
Модель темы , нужно просто для объединения тасков и уроков .
У некоторых тем есть иконка .
Возможно поле icon перекачует в Vertex , а данная модель отвалится за ненадобностью
Модель темы , нужно просто для объединения тасков и уроков .
У некоторых тем есть иконка .
Возможно поле icon перекачует в Vertex , а данная модель отвалится за ненадобностью
"""
icon = models . ImageField ( verbose_name = ' Иконка темы ' , null = True , blank = True )
class CourseRoute ( models . Model ) :
"""
Объединение нескольких мап курса , одназначно
определяет способ прохождения по курсу .
"""
icon = models . ImageField ( verbose_name = u ' Иконка темы ' , null = True , blank = True )
name = models . CharField ( max_length = 255 , verbose_name = ' Имя шаблона ' , blank = True , null = True , unique = True )
maps = models . ManyToManyField ( to = " CourseMap " , verbose_name = " Карта линейного прохождения курсов " )
is_template = models . BooleanField ( default = True , verbose_name = ' Может ли быть использован как шаблон ' )
def is_finish ( self , user ) :
return bool ( sum ( [ int ( i . is_finish ( user ) ) for i in self . maps . all ( ) ] ) )
def get_active_objects ( self , user ) :
return [ i . getactive_object ( user ) for i in self . maps . all ( ) ]
class Meta :
verbose_name = ' Маршрут прохождения '
verbose_name_plural = ' Маршруты прохождения '
class CourseMap ( models . Model ) :
"""
Так как курс евляется связным графом мы можем отобразить его бесконечным количеством способов ,
а нам нужен один самый красивый , мы должный в явном виде указать способ отображения .
Способы отображения курса . Упорядочены в порядке возрастания приоретета .
"""
course = models . OneToOneField ( to = Course )
dependent_elements = models . TextField ( default = ' [] ' )
independent_elements = models . TextField ( default = ' [] ' )
course = models . ForeignKey ( to = Course , verbose_name = ' К какому курсу привязан ' )
def map_to_list ( self ) - > list :
def helper ( root_list ) :
res = [ ]
for i in root_list :
if type ( i ) == type ( [ ] ) :
res + = helper ( i )
@transaction_decorator
def add_vertex ( self , vertex , sort ) :
if sort > self . pivotvertex_set . count ( ) + 1 :
raise ValueError ( " list index out of range " )
for i in self . pivotvertex_set . filter ( sort__gte = sort ) :
i . sort + = 1
i . save ( )
else :
res . append ( i )
pivot = PivotVertex . objects . create ( vertex = vertex , sort = sort , map_course = self )
pivot . save ( )
return pivot
return res
def get_difference ( self , user ) - > list :
return list ( set (
[ i . vertex for i in self . pivotvertex_set . all ( ) ] ) . difference ( set ( user . progress . progress_list . all ( ) )
) )
return helper ( json . loads ( self . dependent_elements ) )
def is_finish ( self , user ) - > bool :
return self . get_difference ( user ) == [ ]
def get_nex t ( self , vertex_id ) - > int :
res_list = self . map_to_list ( )
if not res_list [ - 1 ] == vertex_id :
return res_list [ res_list . index ( vertex_id ) + 1 ]
error = " vertex_id " + str ( vertex_id ) + " last object in list \n " + " , " . join ( [ str ( v ) for v in res_list ] )
raise ValueError ( error )
def get_active_objec t ( self , user ) :
return self . pivotvertex_set . exclude ( vertex__in = self . get_difference ( user ) ) [ 0 ]
class Meta :
verbose_name = ' Карта линейного прохождения курсов '
verbose_name_plural = ' Карты линейного прохождения курсов '
def get_previous ( self , vertex_id ) - > int :
res_list = self . map_to_list ( )
if not res_list [ 0 ] == vertex_id :
return res_list [ res_list . index ( vertex_id ) - 1 ]
error = " vertex_id " + str ( vertex_id ) + " first object in list \n " + " , " . join ( [ str ( v ) for v in res_list ] )
raise ValueError ( error )
def get_first ( self ) :
return self . map_to_list ( ) [ 0 ]
class PivotVertex ( models . Model ) :
vertex = models . ForeignKey ( to = Vertex , verbose_name = " К какому узлу " )
sort = models . SmallIntegerField ( verbose_name = ' Порядок сортировки ' , unique = True )
map_course = models . ForeignKey ( to = CourseMap , verbose_name = ' К какой сортеровке имеетотношение ' , blank = True , null = True )
def get_last ( self ) :
return self . map_to_list ( ) [ - 1 ]
class Meta :
verbose_name = ' Порядок сортировки узла '
verbose_name_plural = ' Порядки сортировок узла '
unique_together = ( ( ' map_course ' , ' vertex ' ) , )
ordering = ( ' sort ' , )