You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

241 lines
7.4 KiB

import arrow
from uuid import uuid4
from django.db import models
from django.utils import timezone
from django.utils.text import slugify
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, Video
User = get_user_model()
class Like(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add=True)
update_at = models.DateTimeField(auto_now=True)
def default_slug():
return str(uuid4())
class Course(BaseModel, DeactivatedMixin):
DRAFT = 0
PENDING = 1
PUBLISHED = 2
ARCHIVED = 3
DENIED = 4
STATUS_CHOICES = (
(DRAFT, 'Draft'),
(PENDING, 'Pending'),
(PUBLISHED, 'Published'),
(ARCHIVED, 'Archived'),
(DENIED, 'Denied')
)
slug = models.SlugField(
allow_unicode=True, null=True, blank=True,
max_length=100, unique=True, db_index=True,
)
author = models.ForeignKey(
User, on_delete=models.SET_NULL, null=True, blank=True
)
title = models.CharField('Название курса', default='', max_length=100, db_index=True)
short_description = models.TextField(
'Краткое описание курса', default='', db_index=True
)
from_author = models.TextField(
'От автора', default='', null=True, blank=True
)
cover = models.ForeignKey(
ImageObject, related_name='course_covers',
verbose_name='Обложка курса', on_delete=models.CASCADE,
null=True, blank=True,
)
price = models.DecimalField(
'Цена курса', help_text='Если цена не выставлена, то курс бесплатный',
max_digits=10, decimal_places=2, null=True, blank=True
)
is_infinite = models.BooleanField(default=False)
deferred_start_at = models.DateTimeField(
'Отложенный запуск курса', help_text='Заполнить если курс отложенный',
null=True, blank=True
)
category = models.ForeignKey('Category', null=True, blank=True, on_delete=models.PROTECT)
duration = models.IntegerField('Продолжительность курса', default=0)
is_featured = models.BooleanField(default=False)
status = models.PositiveSmallIntegerField(
'Статус', 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)
update_at = models.DateTimeField(auto_now=True)
class Meta:
verbose_name = 'Курс'
verbose_name_plural = 'Курсы'
ordering = ['-created_at']
def __str__(self):
return str(self.id) + ' ' + self.title
# def save(self, *args, **kwargs):
# if not self.slug:
# self.slug = slugify(
# self.title[:90],
# allow_unicode=True
# )
# if Course.objects.filter(slug=self.slug).exclude(id=self.id).exists():
# self.slug += '_' + str(uuid4())[:6]
# return super().save()
@property
def url(self):
return self.get_absolute_url()
def get_absolute_url(self):
return reverse_lazy('course', args=[self.id])
@property
def is_free(self):
if self.price:
return False
return True
@property
def deferred_start_at_humanize(self):
return arrow.get(self.deferred_start_at).humanize(locale='ru')
@property
def created_at_humanize(self):
return arrow.get(self.created_at).humanize(locale='ru')
@property
def is_deferred_start(self):
if not self.deferred_start_at:
return False
if timezone.now() < self.deferred_start_at:
return True
return False
@property
def count_videos_in_lessons(self):
return Video.objects.filter(lesson__in=self.lessons.all()).count()
class Category(models.Model):
title = models.CharField('Название категории', max_length=100)
def __str__(self):
return self.title
class Meta:
verbose_name = 'Категория'
verbose_name_plural = 'Категории'
ordering = ['title']
class Lesson(BaseModel, DeactivatedMixin):
title = models.CharField('Название урока', max_length=100)
short_description = models.TextField('Краткое описание урока')
course = models.ForeignKey(
Course, on_delete=models.CASCADE, related_name='lessons'
)
cover = models.ForeignKey(
ImageObject, related_name='lesson_covers',
verbose_name='Обложка урока', on_delete=models.CASCADE,
null=True, blank=True,
)
created_at = models.DateTimeField(auto_now_add=True)
update_at = models.DateTimeField(auto_now=True)
def __str__(self):
return self.title
class Meta:
verbose_name = 'Урок'
verbose_name_plural = 'Уроки'
ordering = ('title',)
class Material(models.Model):
title = models.CharField('Название материала', max_length=100)
cover = models.ForeignKey(
ImageObject, related_name='material_covers',
verbose_name='Обложка материала', on_delete=models.CASCADE,
null=True, blank=True,
)
short_description = models.TextField('Краткое описание материала')
created_at = models.DateTimeField(auto_now_add=True)
update_at = models.DateTimeField(auto_now=True)
def __str__(self):
return self.title
class Meta:
verbose_name = 'Материал'
verbose_name_plural = 'Материалы'
ordering = ('title',)
class Comment(PolymorphicMPTTModel, DeactivatedMixin):
content = models.TextField('Текст комментария', default='')
author = models.ForeignKey(User, on_delete=models.CASCADE)
parent = PolymorphicTreeForeignKey(
'self', null=True, blank=True, related_name='children',
db_index=True, on_delete=models.PROTECT
)
created_at = models.DateTimeField(auto_now_add=True)
update_at = models.DateTimeField(auto_now=True)
@property
def created_at_humanize(self):
return arrow.get(self.created_at).humanize(locale='ru')
def __str__(self):
return self.content
class Meta:
ordering = ('-created_at',)
class MPTTMeta:
order_insertion_by = ['-created_at']
class CourseComment(Comment):
course = models.ForeignKey(
Course, on_delete=models.CASCADE, related_name='comments'
)
class Meta(Comment.Meta):
verbose_name = 'Комментарий курса'
verbose_name_plural = 'Комментарии курсов'
class LessonComment(Comment):
lesson = models.ForeignKey(
Lesson, on_delete=models.CASCADE, related_name='comments'
)
class Meta(Comment.Meta):
verbose_name = 'Комментарий урока'
verbose_name_plural = 'Комментарии уроков'