Exemplo n.º 1
0
class CoursesYearlyLoad(models.Model):
    """
    This model keeps track of how many hours any course needs to do.
    """
    course = models.ForeignKey(Course,
                               on_delete=models.CASCADE,
                               null=False,
                               blank=False,
                               verbose_name=_("course"))
    # A course has both "normal" hours and "bes" hours
    yearly_load = models.IntegerField(null=False,
                                      blank=False,
                                      verbose_name=_("yearly load"))
    yearly_load_bes = models.IntegerField(null=False,
                                          blank=False,
                                          verbose_name=_("yearly load bes"))
    # TODO: Do we want the co teaching hours in a course yearly load? :/

    school = SchoolFromCourseProperty()
    school_year = SchoolYearFromCourseProperty()

    objects = QueryablePropertiesManager()

    def __str__(self):
        return _("{}: {} and {} of bes").format(str(self.course),
                                                self.yearly_load,
                                                self.yearly_load_bes)
Exemplo n.º 2
0
class Stage(models.Model):
    """
    During a stage, a class doesn't have teachers assigned (it is like an holiday, but specific for a given class).
    """
    date_start = models.DateField(null=False,
                                  blank=False,
                                  verbose_name=_("start date"))
    date_end = models.DateField(null=False,
                                blank=False,
                                verbose_name=_("end date"))
    course = models.ForeignKey(Course,
                               null=False,
                               blank=False,
                               on_delete=models.CASCADE,
                               verbose_name=_("course"))
    name = models.CharField(null=True,
                            blank=True,
                            max_length=256,
                            verbose_name=_("name"))

    school = SchoolFromCourseProperty()
    school_year = SchoolYearFromCourseProperty()

    objects = QueryablePropertiesManager()

    def __str__(self):
        return _("{} from {} to {} in {} {}").format(self.name,
                                                     self.date_start,
                                                     self.date_end,
                                                     self.course.year,
                                                     self.course.section)
Exemplo n.º 3
0
class TeachersYearlyLoad(models.Model):
    """
    This model keeps track of how many hours any teacher needs to do in a school, in a certain school year.
    """
    teacher = models.ForeignKey(Teacher,
                                on_delete=models.CASCADE,
                                null=False,
                                blank=False,
                                verbose_name=_("teacher"))
    # A teacher has both "normal" hours and "bes" hours
    yearly_load = models.IntegerField(null=False,
                                      blank=False,
                                      verbose_name=_("yearly load"))
    yearly_load_bes = models.IntegerField(null=False,
                                          blank=False,
                                          verbose_name=_("yearly load bes"))
    yearly_load_co_teaching = models.IntegerField(
        null=False, blank=False, verbose_name=_("yearly load co-teaching"))
    school_year = models.ForeignKey(SchoolYear,
                                    null=False,
                                    blank=False,
                                    on_delete=models.CASCADE,
                                    verbose_name=_("school year"))

    school = SchoolFromTeacherProperty()

    objects = QueryablePropertiesManager()

    def __str__(self):
        return _("{} in {}: {} and {} of bes").format(str(self.teacher),
                                                      str(self.school_year),
                                                      self.yearly_load,
                                                      self.yearly_load_bes)
Exemplo n.º 4
0
class Course(models.Model):
    """
    Course is an alias for the class (like IA and so on)
    """
    year = models.IntegerField(
        blank=False, null=False,
        verbose_name=_("year"))  # in class IA, year is 1
    section = models.CharField(
        max_length=256, blank=False, null=False,
        verbose_name=_("section"))  # In class IA, the section is A
    hour_slots_group = models.ForeignKey(HourSlotsGroup,
                                         on_delete=models.CASCADE,
                                         blank=False,
                                         null=False,
                                         verbose_name=_("hour slots group"))

    school = SchoolFromHourSlotsGroupProperty()
    school_year = SchoolYearFromHourSlotsGroupProperty()

    objects = QueryablePropertiesManager()

    class Meta:
        unique_together = (
            'year',
            'section',
            'hour_slots_group',
        )

    def __str__(self):
        """
        :return: classes as 1 A, 2 Bord and so on (according to what year and section are like)
        """
        return "{} {}, {}".format(str(self.year), self.section,
                                  str(self.hour_slots_group.school_year))
Exemplo n.º 5
0
class AbsenceBlock(models.Model):
    """
    Absence Block keeps track of hours when teachers are not available for teaching
    (It can be used to accommodate teachers with part-time contracts, or special needs)
    """
    teacher = models.ForeignKey(Teacher,
                                on_delete=models.CASCADE,
                                null=False,
                                blank=False,
                                verbose_name=_("teacher"))
    hour_slot = models.ForeignKey(HourSlot,
                                  on_delete=models.CASCADE,
                                  null=False,
                                  blank=False,
                                  verbose_name=_("hour slot"))

    school = SchoolFromHourSlotProperty()
    school_year = SchoolYearFromHourSlotProperty()

    objects = QueryablePropertiesManager()

    def __str__(self):
        """
        :return:
        """
        return "{}, {}, {}".format(str(self.teacher), str(self.hour_slot),
                                   str(self.school_year))
class ApplicationWithClassBasedProperties(Application):
    categories = models.ManyToManyField(CategoryWithClassBasedProperties,
                                        related_name='applications')

    objects = QueryablePropertiesManager()

    highest_version = SubqueryFieldProperty(
        lambda: (VersionWithClassBasedProperties.objects.select_properties(
            'version').filter(application=models.OuterRef('pk')).order_by(
                '-major', '-minor', '-patch')),
        field_name='version',
        output_field=models.CharField())
    version_count = VersionCountProperty()
    major_sum = AggregateProperty(models.Sum('versions__major'))
    major_avg = MajorAverageProperty()
    if DJANGO_VERSION < (1, 8):
        support_start_date = AggregateProperty(
            models.Min('versions__supported_from'))
    else:
        support_start_date = AggregateProperty(
            models.Min('versions__supported_from',
                       output_field=models.DateField(null=True)))
    lowered_version_changes = LoweredVersionChangesProperty()
    has_version_with_changelog = RelatedExistenceCheckProperty(
        'versions__changes')
    dummy = DummyProperty()

    class Meta:
        verbose_name = 'Application'
class ApplicationWithDecoratorBasedProperties(Application):
    categories = models.ManyToManyField(CategoryWithDecoratorBasedProperties,
                                        related_name='applications')

    objects = QueryablePropertiesManager()

    class Meta:
        verbose_name = 'Application'

    @queryable_property
    def highest_version(self):
        try:
            return self.versions.order_by('-major', '-minor',
                                          '-patch')[0].version
        except IndexError:
            return None

    @highest_version.annotater
    @classmethod
    def highest_version(cls):
        queryset = VersionWithDecoratorBasedProperties.objects.select_properties(
            'version')
        queryset = queryset.filter(application=models.OuterRef('pk')).order_by(
            '-major', '-minor', '-patch')
        return models.Subquery(queryset.values('version')[:1],
                               output_field=models.CharField())

    @queryable_property(annotation_based=True)
    @classmethod
    def version_count(cls):
        return models.Count('versions')

    @queryable_property(annotation_based=True)
    @classmethod
    def support_start_date(cls):
        return models.Min('versions__supported_from')

    @queryable_property
    def major_sum(self):
        return self.versions.aggregate(
            major_sum=models.Sum('major'))['major_sum']

    @major_sum.annotater
    @classmethod
    def major_sum(cls):
        return models.Sum('versions__major')

    lowered_version_changes = queryable_property()

    @lowered_version_changes.annotater
    @classmethod
    def lowered_version_changes(cls):
        from django.db.models.functions import Lower
        return Lower('versions__changes_or_default')
class CategoryWithClassBasedProperties(Category):
    objects = QueryablePropertiesManager()

    has_versions = RelatedExistenceCheckProperty('applications__versions')
    version_count = AnnotationProperty(models.Count('applications__versions'))
    has_v2 = SubqueryExistenceCheckProperty(
        lambda: VersionWithClassBasedProperties.objects.filter(
            application__categories=models.OuterRef('pk'), major=2))
    circular = CircularProperty()

    class Meta:
        verbose_name = 'Category'
class CategoryWithDecoratorBasedProperties(Category):
    objects = QueryablePropertiesManager()

    class Meta:
        verbose_name = 'Category'

    @queryable_property
    def circular(self):
        raise NotImplementedError()

    @circular.annotater
    @classmethod
    def circular(cls):
        return models.F('circular')
Exemplo n.º 10
0
class HourSlot(models.Model):
    """
    HourSlot is used to store the time interval of first, second, third and so on hours.
    Every school, in fact, keeps them separately.
    """
    hour_number = models.IntegerField(
        blank=False, null=False, verbose_name=_("hour number")
    )  # Used to store first, second third hour and so on.
    starts_at = models.TimeField(null=False,
                                 blank=False,
                                 verbose_name=_("begins at"))
    ends_at = models.TimeField(null=False,
                               blank=False,
                               verbose_name=_("ends at"))
    day_of_week = models.IntegerField(choices=DAYS_OF_WEEK,
                                      null=False,
                                      blank=False,
                                      verbose_name=_("day of the week"))
    # This counts the effective duration of each lecture (e.g., lectures of 55' actually are worth 1 hour)
    legal_duration = models.DurationField(null=False,
                                          blank=False,
                                          verbose_name=_("legal duration"))
    hour_slots_group = models.ForeignKey(HourSlotsGroup,
                                         on_delete=models.CASCADE,
                                         null=False,
                                         blank=False,
                                         verbose_name=_("hour slots group"))

    school = SchoolFromHourSlotsGroupProperty()
    school_year = SchoolYearFromHourSlotsGroupProperty()

    objects = QueryablePropertiesManager()

    def __str__(self):
        """
        :return: hourslots like "Monday, 8:00-9:00 2019/2020"
        """
        return "{}, {}-{} {}/{} ({})".format(
            DAYS_OF_WEEK[self.day_of_week][1],
            self.starts_at.strftime("%H:%M"), self.ends_at.strftime("%H:%M"),
            str(self.hour_slots_group.school_year.year_start),
            str(self.hour_slots_group.school_year.year_start + 1),
            self.hour_slots_group.name)
Exemplo n.º 11
0
class HoursPerTeacherInClass(models.Model):
    """
    This model keeps track of how many hours any teacher has in every class.
    """
    teacher = models.ForeignKey(Teacher,
                                on_delete=models.CASCADE,
                                null=False,
                                blank=False,
                                verbose_name=_("teacher"))
    course = models.ForeignKey(Course,
                               null=False,
                               blank=False,
                               on_delete=models.CASCADE,
                               verbose_name=_("course"))
    subject = models.ForeignKey(Subject,
                                null=False,
                                blank=False,
                                on_delete=models.CASCADE,
                                verbose_name=_("subject"))

    # A teacher has "normal" hours, "bes" hours and co-teaching hours.
    hours = models.IntegerField(null=False,
                                blank=False,
                                verbose_name=_("hours"))
    hours_bes = models.IntegerField(null=False,
                                    blank=False,
                                    verbose_name=_("hours BES"))
    hours_co_teaching = models.IntegerField(
        null=False, blank=False, verbose_name=_("Hours co-teaching"))

    school = SchoolFromCourseProperty()
    school_year = SchoolYearFromCourseProperty()

    objects = QueryablePropertiesManager()

    def __str__(self):
        return str(self.teacher) + " - " + str(
            self.course) + " " + self.subject.name
class VersionWithClassBasedProperties(Version):
    application = models.ForeignKey(ApplicationWithClassBasedProperties,
                                    on_delete=models.CASCADE,
                                    related_name='versions')

    objects = QueryablePropertiesManager()

    major_minor = MajorMinorVersionProperty()
    version = FullVersionProperty()
    changes_or_default = DefaultChangesProperty()
    is_version_2 = Version2Property()
    shares_common_data = ValueCheckProperty('application.common_data', 0)
    released_in_2018 = ValueCheckProperty('supported_from.year', 2018)
    is_supported = RangeCheckProperty('supported_from',
                                      'supported_until',
                                      date(2019, 1, 1),
                                      include_missing=True)
    supported_in_2018 = RangeCheckProperty('supported_from.year',
                                           'supported_until.year',
                                           2018,
                                           include_missing=True)

    class Meta:
        verbose_name = 'Version'
Exemplo n.º 13
0
class Assignment(models.Model):
    """
    Assignment for a teacher in a class.
    Every hour has a different assignment.
    (Monday the 1st and Monday the 8th have two different assignments for the same teacher, hour_slot, class and room).
    """
    teacher = models.ForeignKey(Teacher,
                                on_delete=models.CASCADE,
                                null=False,
                                blank=False,
                                verbose_name=_("teacher"))
    course = models.ForeignKey(Course,
                               null=False,
                               blank=False,
                               on_delete=models.CASCADE,
                               verbose_name=_("course"))
    subject = models.ForeignKey(Subject,
                                null=False,
                                blank=False,
                                on_delete=models.CASCADE,
                                verbose_name=_("subject"))
    room = models.ForeignKey(Room,
                             null=True,
                             blank=True,
                             on_delete=models.CASCADE,
                             verbose_name=_("room"))

    date = models.DateField(null=False, blank=False, verbose_name=_("date"))

    # Both hour start and hour end should coincide with the HourSlot if the hour is not special.
    hour_start = models.TimeField(null=False,
                                  blank=False,
                                  verbose_name=_("start hour"))
    hour_end = models.TimeField(null=False,
                                blank=False,
                                verbose_name=_("end hour"))
    bes = models.BooleanField(null=False,
                              blank=False,
                              default=False,
                              verbose_name=_("BES"))
    co_teaching = models.BooleanField(null=False,
                                      blank=False,
                                      default=False,
                                      verbose_name=_("Co-teaching"))
    substitution = models.BooleanField(null=False,
                                       blank=False,
                                       default=False,
                                       verbose_name=_("substitution"))
    substituted_assignment = models.ForeignKey(
        "self",
        on_delete=models.CASCADE,
        null=True,
        blank=True,
        default=None,
        verbose_name=_("substituted assignment"))
    absent = models.BooleanField(
        null=False, blank=False, default=False,
        verbose_name=_("absence"))  # for substituted teachers

    # it means that the substitution should not be considered when counting the total hours of substitutions
    free_substitution = models.BooleanField(
        null=False,
        blank=False,
        default=False,
        verbose_name=_("free substitution"))

    school = SchoolFromCourseProperty()
    school_year = SchoolYearFromCourseProperty()

    objects = QueryablePropertiesManager()

    def __str__(self):
        return "{}; {}; {}; {}; {} - {}".format(
            self.teacher, self.course,
            self.room if self.room is not None else _("No room"), self.date,
            self.hour_start, self.hour_end)
class VersionWithDecoratorBasedProperties(Version):
    application = models.ForeignKey(ApplicationWithDecoratorBasedProperties,
                                    on_delete=models.CASCADE,
                                    related_name='versions')

    objects = QueryablePropertiesManager()

    class Meta:
        verbose_name = 'Version'

    @queryable_property
    def major_minor(self):
        return '{major}.{minor}'.format(major=self.major, minor=self.minor)

    @major_minor.filter
    @classmethod
    def major_minor(cls, lookup, value):
        if lookup != 'exact':
            raise NotImplementedError()
        parts = value.split('.')
        return models.Q(major=parts[0], minor=parts[1])

    @major_minor.updater
    @classmethod
    def major_minor(cls, value):
        parts = value.split('.')
        return dict(major=parts[0], minor=parts[1])

    @queryable_property
    def version(self):
        return '{major_minor}.{patch}'.format(major_minor=self.major_minor,
                                              patch=self.patch)

    @version.setter
    def version(self, value):
        self.major, self.minor, self.patch = value.split('.')

    @version.annotater
    @classmethod
    def version(cls):
        from django.db.models.functions import Concat
        return Concat('major',
                      models.Value('.'),
                      'minor',
                      models.Value('.'),
                      'patch',
                      output_field=models.CharField())

    @version.filter(requires_annotation=False, lookups=('exact', ))
    @classmethod
    def version(cls, lookup, value):
        parts = value.rsplit('.', 1)
        return models.Q(major_minor=parts[0], patch=parts[1])

    @version.updater
    @classmethod
    def version(cls, value):
        parts = value.rsplit('.', 1)
        return dict(major_minor=parts[0], patch=parts[1])

    @queryable_property
    def changes_or_default(self):
        return self.changes or '(No data)'

    @changes_or_default.annotater
    @classmethod
    def changes_or_default(cls):
        from django.db.models import Value
        from django.db.models.functions import Coalesce
        return Coalesce('changes',
                        Value('(No data)'),
                        output_field=models.TextField())

    @queryable_property
    def is_version_2(self):
        return self.major == 2

    @is_version_2.filter(boolean=True)
    @classmethod
    def is_version_2(cls):
        return models.Q(major=2)