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.
 
 

166 lines
6.1 KiB

import os
from decimal import Decimal
import math
from django.db import models
from django.db.models import TextChoices
from django.utils.translation import gettext_lazy as _
from filer.fields.image import FilerImageField
from filer.fields.file import FilerFileField
from apps.account.models import ProfessorUser
from utils.schema import default_timing
from utils import generate_slug_for_model
def course_file_upload_to(instance, filename):
return os.path.join(f"courses/{instance.slug}/videos/{filename}")
def attachment_file_upload_to(instance, filename):
return os.path.join(f"courses/{instance.course.slug}/attachments/{filename}")
class CourseCategory(models.Model):
name = models.CharField(max_length=255, verbose_name='Category Name')
slug = models.SlugField(unique=True, max_length=255)
def __str__(self):
return self.name
def save(self, *args, **kwargs):
self.slug = generate_slug_for_model(CourseCategory, self.name)
super().save(*args, **kwargs)
@property
def course_count(self):
return self.courses.count()
class Course(models.Model):
class LevelChoices(TextChoices):
BEGINNER = 'beginner', 'Beginner'
MID = 'mid', 'Mid Level'
ADVANCED = 'advanced', 'Advanced'
class StatusChoices(TextChoices):
INACTIVE = 'inactive', 'Inactive' # Not Active (does not show)
UPCOMING = 'upcoming', 'Upcoming' # Upcoming (visible but registration not allowed)
REGISTERING = 'registering', 'Registering' # Registering (registration is open)
ONGOING = 'ongoing', 'Ongoing' # Ongoing (course has started, registration closed)
FINISHED = 'finished', 'Finished' # Finished (course has ended)
class VedioTypeChoices(models.TextChoices):
VIDEO_FILE = 'video_file', 'Video File'
VIDEO_LINK = 'video_link', 'Video Link'
title = models.CharField(max_length=255, verbose_name='Course Title')
slug = models.SlugField(allow_unicode=True, unique=True)
category = models.ForeignKey(CourseCategory, on_delete=models.CASCADE, related_name='courses', verbose_name='Category')
professor = models.ForeignKey(
ProfessorUser,
on_delete=models.CASCADE,
related_name="courses"
)
thumbnail = FilerImageField(
related_name='+', on_delete=models.PROTECT, null=True, blank=True,
verbose_name=_('thumbnail')
)
video_type = models.CharField(max_length=20, choices=VedioTypeChoices.choices, verbose_name='Vedio Type')
video_file = models.FileField(
upload_to=course_file_upload_to,
null=True,
blank=True
)
video_link = models.CharField(max_length=500, null=True, blank=True, verbose_name='Video Link')
is_online = models.BooleanField(default=True, verbose_name='Is Online Course')
level = models.CharField(max_length=10, choices=LevelChoices.choices, verbose_name='Course Level')
duration = models.PositiveIntegerField(verbose_name='Duration (in hours)')
lessons_count = models.PositiveIntegerField(verbose_name='Number of Lessons')
description = models.TextField(verbose_name='Course Description')
short_description = models.CharField(max_length=500, blank=True, null=True, verbose_name="Short Description")
status = models.CharField(max_length=15, choices=StatusChoices.choices, default=StatusChoices.INACTIVE, verbose_name='Course Status')
is_free = models.BooleanField(default=True, verbose_name='Is Free')
price = models.DecimalField(max_digits=10, decimal_places=2, default=0.00, verbose_name='Course Price')
discount_percentage = models.PositiveIntegerField(default=0, verbose_name='Discount Percentage')
final_price = models.DecimalField(
verbose_name=_('Course Final Price'), decimal_places=2, max_digits=10, default=0.00, blank=True,
help_text=_('This field is automatically calculated based on the discount percentage.')
)
timing = models.JSONField(blank=True, null=True, default=default_timing, verbose_name=_("Timing"), help_text=_("The Timing information in JSON format."))
features = models.JSONField(verbose_name=_('Course features'), default=dict, blank=True, null=True)
def __str__(self):
return self.title
def save(self, *args, **kwargs):
self.slug = generate_slug_for_model(Course, self.title)
if self.discount_percentage > 0:
discount_amount = (self.price * self.discount_percentage) / 100
final_price = self.price - discount_amount
self.final_price = Decimal(math.ceil(final_price)).quantize(Decimal('0.00'))
else:
self.final_price = Decimal(math.ceil(self.price)).quantize(Decimal('0.00'))
super().save(*args, **kwargs)
class Meta:
verbose_name = "Course"
verbose_name_plural = "Courses"
class Glossary(models.Model):
course = models.ForeignKey(Course, on_delete=models.CASCADE, related_name='glossaries', verbose_name='Course')
title = models.CharField(max_length=555, verbose_name='Glossary Title')
description = models.TextField(verbose_name='Description')
def __str__(self):
return f"{self.course.title} - {self.title}"
class Meta:
ordering = ("-id",)
verbose_name = "Glossary"
verbose_name_plural = "Glossary"
class Attachment(models.Model):
course = models.ForeignKey(Course, on_delete=models.CASCADE, related_name='attachments', verbose_name='Course')
title = models.CharField(max_length=255, verbose_name='Attachment Title')
file = models.FileField(
upload_to=attachment_file_upload_to,
verbose_name='Attachment File'
)
file_size = models.PositiveIntegerField(verbose_name='File Size (in bytes)', null=True, blank=True)
def save(self, *args, **kwargs):
# Calculate the file size before saving
if self.file and not self.file_size:
self.file_size = self.file.size
super().save(*args, **kwargs)
def __str__(self):
return f"{self.course.title} - {self.title}"
class Meta:
ordering = ("-id",)
verbose_name = "Attachment"
verbose_name_plural = "Attachments"