Repository URL to install this package:
|
Version:
5.5.0 ▾
|
# -*- coding: utf-8 -*-
import random
from django.db import connection, models
from django.db.models import Q
from django.utils.timezone import now, timedelta
from . import settings as courses_settings
def annotate_with_public_courses(queryset):
"""
Annotate a queryset with a "public_courses_count" attribute.
queryset: refer to a model with a `courses` attribute.
"""
return queryset.filter(
courses__is_active=True, courses__show_in_catalog=True
).annotate(public_courses_count=models.Count("courses"))
class CourseSubjectManager(models.Manager):
def by_score(self):
return self.order_by("-score", "name")
def featured(self):
return self.filter(featured=True).exclude(image="")
def random_featured(self):
return self.featured().order_by("?")
class CourseQuerySet(models.query.QuerySet):
@property
def too_late(self):
return now() + timedelta(days=courses_settings.NUMBER_DAYS_TOO_LATE)
def too_late_range(self):
return (now(), self.too_late)
def with_related(self):
queryset = self.prefetch_related(
"subjects", "universities", "related_universities"
)
return queryset
def public(self):
return self.filter(is_active=True, show_in_catalog=True)
def starting_soon(self):
return self.public().filter(start_date__gt=now())
def ending_soon(self):
return self.public().filter(end_date__range=self.too_late_range())
def enrollment_ends_soon(self):
return self.public().filter(enrollment_end_date__range=self.too_late_range())
def new(self):
"""
A new course is in its first session and for which enrollment is not closed.
"""
return self.public().filter(
Q(session_number=1),
Q(enrollment_end_date__gte=now()) | Q(enrollment_end_date__isnull=True),
)
def opened(self):
"""
A course that is currently opened for enrollment.
"""
_now = now()
return self.public().filter(
Q(enrollment_start_date__lte=_now) | Q(enrollment_start_date__isnull=True),
Q(enrollment_end_date__gte=_now) | Q(enrollment_end_date__isnull=True),
Q(end_date__gte=_now) | Q(end_date__isnull=True),
)
def started(self):
"""
A course that is on-going.
"""
return self.public().filter(
Q(start_date__lte=now()) | Q(start_date__isnull=True),
Q(end_date__gte=now()) | Q(end_date__isnull=True),
)
def archived(self):
"""
A course is archived if it has an end date and enrollment end date in the past.
"""
return self.public().filter(
end_date__lt=now(),
end_date__isnull=False,
enrollment_end_date__isnull=False,
)
def browsable(self):
"""
A course is browsable if it has an end date in the past but enrollment is still open.
"""
return self.public().filter(
end_date__lt=now(), end_date__isnull=False, enrollment_end_date__isnull=True
)
def annotate_for_ordering(self):
"""
Add attributes to all results for ordering purposes:
1) has_ended: course that have ended will always be at the end,
2) is_enrollment_over: courses for which enrollment is over will come
after the ones that are still open,
3) has_started: courses that have started will always be presented
before courses that have yet to start,
4) ordering_date: Lastly, if the course is started we will use its end
of enrollment date to rank it, otherwise we will use its start date.
"""
# We are putting raw sql in the extra(...) statement. To do that,
# we need the proper datetime formatting, which varies for every db.
formatted_now = connection.ops.value_to_db_datetime(now())
return self.extra(
select={
"has_ended": '(end_date IS NOT NULL AND end_date < "{now}")'.format(
now=formatted_now
),
"is_enrollment_over": (
'(enrollment_end_date IS NOT NULL AND enrollment_end_date < "{now}")'
).format(now=formatted_now),
"has_started": '(start_date < "{now}" OR start_date IS NULL)'.format(
now=formatted_now
),
"ordering_date": (
'CASE WHEN start_date < "{now}" OR start_date IS NULL '
"THEN enrollment_end_date ELSE start_date END"
).format(now=formatted_now),
}
)
def by_score(self):
return self.public().order_by("-score")
def random_featured(self, limit_to=7):
courses = self.by_score().prefetch_related("related_universities__university")[
:limit_to
]
courses = list(courses)
random.shuffle(courses)
return courses