Skip to content
Snippets Groups Projects
Verified Commit d62e075b authored by Jonathan Weth's avatar Jonathan Weth :keyboard:
Browse files

Implement detailed students list and include it on several positions

- My groups
- My students
- Links in week view
parent d897a1a2
No related branches found
No related tags found
No related merge requests found
Pipeline #4106 failed
Showing
with 539 additions and 99 deletions
from datetime import date from datetime import date
from typing import Dict, Iterator, Optional, Union from typing import Dict, Iterable, Iterator, Optional, Union
from django.db.models import Exists, OuterRef, Q, QuerySet from django.db.models import Exists, OuterRef, Q, QuerySet
from django.db.models.aggregates import Count from django.db.models.aggregates import Count, Sum
from django.utils.translation import gettext as _ from django.utils.translation import gettext as _
import reversion import reversion
...@@ -282,3 +282,77 @@ def get_owner_groups_with_lessons(self: Person): ...@@ -282,3 +282,77 @@ def get_owner_groups_with_lessons(self: Person):
Groups which have child groups with related lessons are also included. Groups which have child groups with related lessons are also included.
""" """
return Group.get_groups_with_lessons().filter(owners=self) return Group.get_groups_with_lessons().filter(owners=self)
@Group.method
def generate_person_list_with_class_register_statistics(
self: Group, persons: Optional[Iterable] = None
) -> QuerySet:
"""Get with class register statistics annotated list of all members."""
persons = persons or self.members.all()
persons = persons.filter(
personal_notes__groups_of_person=self,
personal_notes__lesson_period__lesson__validity__school_term=self.school_term,
).annotate(
absences_count=Count(
"personal_notes__absent",
filter=Q(
personal_notes__absent=True,
personal_notes__lesson_period__lesson__validity__school_term=self.school_term,
),
),
excused=Count(
"personal_notes__absent",
filter=Q(
personal_notes__absent=True,
personal_notes__excused=True,
personal_notes__excuse_type__isnull=True,
personal_notes__lesson_period__lesson__validity__school_term=self.school_term,
),
),
unexcused=Count(
"personal_notes__absent",
filter=Q(
personal_notes__absent=True,
personal_notes__excused=False,
personal_notes__lesson_period__lesson__validity__school_term=self.school_term,
),
),
tardiness=Sum("personal_notes__late"),
tardiness_count=Count(
"personal_notes",
filter=~Q(personal_notes__late=0)
& Q(
personal_notes__lesson_period__lesson__validity__school_term=self.school_term,
),
),
)
for extra_mark in ExtraMark.objects.all():
persons = persons.annotate(
**{
extra_mark.count_label: Count(
"personal_notes",
filter=Q(
personal_notes__extra_marks=extra_mark,
personal_notes__lesson_period__lesson__validity__school_term=self.school_term,
),
)
}
)
for excuse_type in ExcuseType.objects.all():
persons = persons.annotate(
**{
excuse_type.count_label: Count(
"personal_notes__absent",
filter=Q(
personal_notes__absent=True,
personal_notes__excuse_type=excuse_type,
personal_notes__lesson_period__lesson__validity__school_term=self.school_term,
),
)
}
)
return persons
...@@ -146,6 +146,14 @@ add_perm("alsijil.view_my_students", view_my_students_predicate) ...@@ -146,6 +146,14 @@ add_perm("alsijil.view_my_students", view_my_students_predicate)
view_my_groups_predicate = has_person & is_teacher view_my_groups_predicate = has_person & is_teacher
add_perm("alsijil.view_my_groups", view_my_groups_predicate) add_perm("alsijil.view_my_groups", view_my_groups_predicate)
# View students list
view_students_list_predicate = view_my_groups_predicate & (
is_group_owner
| has_global_perm("alsijil.view_personalnote")
| has_object_perm("core.view_personalnote_group")
)
add_perm("alsijil.view_students_list", view_students_list_predicate)
# View person overview # View person overview
view_person_overview_predicate = has_person & ( view_person_overview_predicate = has_person & (
(is_current_person & is_site_preference_set("alsijil", "view_own_personal_notes")) (is_current_person & is_site_preference_set("alsijil", "view_own_personal_notes"))
......
table.datatable a { table.datatable a {
color: inherit !important; color: inherit !important;
} }
table a.tr-link { table a.tr-link {
display: block; display: block;
width: inherit; width: inherit;
height: inherit; height: inherit;
} }
.collapsible-icon-right { .collapsible-icon-right {
align-self: end; align-self: end;
flex-grow: 100; flex-grow: 100;
text-align: right!important; text-align: right !important;
} }
@media only screen and (min-width: 1201px) { @media only screen and (min-width: 1201px) {
...@@ -30,8 +30,32 @@ table a.tr-link { ...@@ -30,8 +30,32 @@ table a.tr-link {
.collection .collection-item.avatar { .collection .collection-item.avatar {
padding-left: 20px; padding-left: 20px;
} }
.collection .collection-item.avatar:not(.circle-clipper) > .circle { .collection .collection-item.avatar:not(.circle-clipper) > .circle {
position: relative; position: relative;
margin-bottom: 10px; margin-bottom: 10px;
} }
} }
.collapsible li .show-on-active {
display: none;
}
.collapsible li.active .show-on-active {
display: block;
}
th.chip-height {
height: 67px;
line-height: 2.2;
}
.collection-item.chip-height {
height: 52px;
line-height: 2.2;
}
li.collection-item.button-height {
height: 58px;
line-height: 2.5;
}
{# -*- engine:django -*- #} {# -*- engine:django -*- #}
{% extends "core/base.html" %} {% extends "core/base.html" %}
{% load i18n %} {% load i18n static %}
{% block browser_title %}{% blocktrans %}My groups{% endblocktrans %}{% endblock %} {% block browser_title %}{% blocktrans %}My groups{% endblocktrans %}{% endblock %}
{% block page_title %} {% block page_title %}
{% blocktrans %}My groups{% endblocktrans %} {% blocktrans %}My groups{% endblocktrans %}
{% endblock %} {% endblock %}
{% block extra_head %}
{{ block.super }}
<link rel="stylesheet" href="{% static 'css/alsijil/alsijil.css' %}"/>
{% endblock %}
{% block content %} {% block content %}
<div class="collection"> <table class="highlight responsive-table hide-on-med-and-down">
<thead>
<tr>
<th>{% trans "Name" %}</th>
<th>{% trans "Students" %}</th>
<th></th>
</tr>
</thead>
{% for group in groups %} {% for group in groups %}
<a class="collection-item" href="{% url "week_view" "group" group.pk %}"> <tr>
{{ group }} <td>
</a> {{ group }}
</td>
<td>{{ group.students_count }}</td>
<td>
<div class="right">
<a class="btn primary-color waves-effect waves-light" href="{% url "students_list" group.pk %}">
<i class="material-icons left">people</i>
{% trans "Students list" %}
</a>
<a class="btn secondary-color waves-effect waves-light" href="{% url "week_view" "group" group.pk %}">
<i class="material-icons left">view_week</i>
{% trans "Week view" %}
</a>
<a class="btn primary waves-effect waves-light" href="{% url "full_register_group" group.pk %}"
target="_blank">
<i class="material-icons left">print</i>
{% trans "Generate printout" %}
</a>
</div>
</td>
</tr>
{% empty %} {% empty %}
<li class="collection-item flow-text"> <tr>
{% blocktrans %}No groups available.{% endblocktrans %} <td class="flow-text" colspan="3">
</li> {% blocktrans %}No groups available.{% endblocktrans %}
</td>
</tr>
{% endfor %} {% endfor %}
</table>
<div class="hide-on-large-only">
<ul class="collection">
{% for group in groups %}
<li class="collection-item">
<span class="title">{{ group }}</span>
<p>
{{ group.students_count }} {% trans "students" %}
</p>
<p>
<a class="btn primary-color waves-effect waves-light" href="{% url "week_view" "group" group.pk %}">
<i class="material-icons left">people</i>
{% trans "Students list" %}
</a>
</p>
<p>
<a class="btn secondary-color waves-effect waves-light" href="{% url "week_view" "group" group.pk %}">
<i class="material-icons left">view_week</i>
{% trans "Week view" %}
</a>
</p>
<p>
<a class="btn primary waves-effect waves-light" href="{% url "full_register_group" group.pk %}"
target="_blank">
<i class="material-icons left">print</i>
{% trans "Generate printout" %}
</a>
</p>
</li>
{% empty %}
<li class="collection-item flow-text">
{% blocktrans %}No groups available.{% endblocktrans %}
</li>
{% endfor %}
</ul>
</div> </div>
{% endblock %} {% endblock %}
{# -*- engine:django -*- #} {# -*- engine:django -*- #}
{% extends "core/base.html" %} {% extends "core/base.html" %}
{% load data_helpers %} {% load i18n week_helpers data_helpers static time_helpers %}
{% load week_helpers %}
{% load i18n %}
{% block browser_title %}{% blocktrans %}My students{% endblocktrans %}{% endblock %} {% block browser_title %}{% blocktrans %}My students{% endblocktrans %}{% endblock %}
...@@ -11,16 +9,56 @@ ...@@ -11,16 +9,56 @@
{% blocktrans %}My students{% endblocktrans %} {% blocktrans %}My students{% endblocktrans %}
{% endblock %} {% endblock %}
{% block extra_head %}
{{ block.super }}
<link rel="stylesheet" href="{% static 'css/alsijil/alsijil.css' %}"/>
{% endblock %}
{% block content %} {% block content %}
<div class="collection"> <ul class="collapsible">
{% for person in persons %} {% for group, persons in groups %}
<a class="collection-item" href="{% url "overview_person" person.pk %}"> <li {% if forloop.first %}class="active"{% endif %}>
{{ person }} <div class="collapsible-header">
</a> <div class="hundred-percent">
{% empty %} <span class="right show-on-active hide-on-small-and-down">
<li class="collection-item flow-text"> <a class="btn primary-color waves-effect waves-light" href="{% url "week_view" "group" group.pk %}">
{% blocktrans %}No students available.{% endblocktrans %} <i class="material-icons left">view_week</i>
{% trans "Week view" %}
</a>
<a class="btn waves-effect waves-light" href="{% url "full_register_group" group.pk %}" target="_blank">
<i class="material-icons left">print</i>
{% trans "Generate printout" %}
</a>
</span>
<h6>{{ group.name }}
<span class="chip">{{ group.school_term }}</span>
</h6>
<p class="show-on-active hide-on-med-and-up">
<a class="btn primary-color waves-effect waves-light hundred-percent"
href="{% url "week_view" "group" group.pk %}">
<i class="material-icons left">view_week</i>
{% trans "Week view" %}
</a>
</p>
<p class="show-on-active hide-on-med-and-up">
<a class="btn waves-effect waves-light hundred-percent" href="{% url "full_register_group" group.pk %}"
target="_blank">
<i class="material-icons left">print</i>
{% trans "Generate printout" %}
</a>
</p>
</div>
</div>
<div class="collapsible-body">
{% include "alsijil/partials/persons_with_stats.html" with persons=persons %}
</div>
</li> </li>
{% endfor %} {% endfor %}
</div> </ul>
{% include "alsijil/partials/legend.html" %}
{% endblock %} {% endblock %}
{# -*- engine:django -*- #}
{% extends "core/base.html" %}
{% load static time_helpers data_helpers week_helpers i18n %}
{% block browser_title %}{% blocktrans with group=group %}Students list: {{ group }}{% endblocktrans %}{% endblock %}
{% block page_title %}
<a href="{% url "my_groups" %}"
class="btn-flat primary-color-text waves-light waves-effect">
<i class="material-icons left">chevron_left</i> {% trans "Back" %}
</a>
{% blocktrans with group=group %}Students list: {{ group }}{% endblocktrans %}
<span class="right show-on-active hide-on-small-and-down">
<a class="btn primary-color waves-effect waves-light" href="{% url "week_view" "group" group.pk %}">
<i class="material-icons left">view_week</i>
{% trans "Week view" %}
</a>
<a class="btn waves-effect waves-light" href="{% url "full_register_group" group.pk %}" target="_blank">
<i class="material-icons left">print</i>
{% trans "Generate printout" %}
</a>
</span>
{% endblock %}
{% block extra_head %}
{{ block.super }}
<link rel="stylesheet" href="{% static 'css/alsijil/alsijil.css' %}"/>
{% endblock %}
{% block content %}
<p class="show-on-active hide-on-med-and-up">
<a class="btn primary-color waves-effect waves-light hundred-percent"
href="{% url "week_view" "group" group.pk %}">
<i class="material-icons left">view_week</i>
{% trans "Week view" %}
</a>
</p>
<p class="show-on-active hide-on-med-and-up">
<a class="btn waves-effect waves-light hundred-percent" href="{% url "full_register_group" group.pk %}"
target="_blank">
<i class="material-icons left">print</i>
{% trans "Generate printout" %}
</a>
</p>
{% include "alsijil/partials/persons_with_stats.html" with persons=persons %}
{% include "alsijil/partials/legend.html" %}
{% endblock %}
...@@ -15,14 +15,7 @@ ...@@ -15,14 +15,7 @@
{{ week_select|json_script:"week_select" }} {{ week_select|json_script:"week_select" }}
<script type="text/javascript" src="{% static "js/chronos/week_select.js" %}"></script> <script type="text/javascript" src="{% static "js/chronos/week_select.js" %}"></script>
<div class="row"> <div class="row">
{% if group %} <div class="col s12">
<div class="col s12 m2 push-m10 l1 push-l11">
<a class="col s12 btn waves-effect waves-light right" href="{% url 'full_register_group' group.id %}">
<i class="material-icons center">print</i>
</a>
</div>
{% endif %}
<div class="col s12 {% if group %}m10 pull-m2 l11 pull-l1 {% endif %}">
<form method="post" action=""> <form method="post" action="">
{% csrf_token %} {% csrf_token %}
{% form form=select_form %}{% endform %} {% form form=select_form %}{% endform %}
...@@ -34,12 +27,39 @@ ...@@ -34,12 +27,39 @@
</div> </div>
<div class="row"> <div class="row no-margin">
<h4 class="col s12 m6">{% blocktrans with el=el week=week.week %}CW {{ week }}: <h4 class="col s12 m6">{% blocktrans with el=el week=week.week %}CW {{ week }}:
{{ instance }}{% endblocktrans %} </h4> {{ instance }}{% endblocktrans %} </h4>
{% include "chronos/partials/week_select.html" with wanted_week=week %} {% include "chronos/partials/week_select.html" with wanted_week=week %}
</div> </div>
{% if group %}
<p class="hide-on-med-and-down">
<a class="btn primary-color waves-effect waves-light" href="{% url "students_list" group.pk %}">
<i class="material-icons left">people</i>
{% trans "Students list" %}
</a>
<a class="btn waves-effect waves-light" href="{% url "full_register_group" group.pk %}" target="_blank">
<i class="material-icons left">print</i>
{% trans "Generate printout" %}
</a>
</p>
<p class="hide-on-med-and-up">
<a class="btn primary-color waves-effect waves-light hundred-percent" href="{% url "students_list" group.pk %}">
<i class="material-icons left">people</i>
{% trans "Students list" %}
</a>
</p>
<p class="hide-on-med-and-up">
<a class="btn waves-effect waves-light hundred-percent" href="{% url "full_register_group" group.pk %}"
target="_blank">
<i class="material-icons left">print</i>
{% trans "Generate printout" %}
</a>
</p>
{% endif %}
{% if lesson_periods %} {% if lesson_periods %}
<div class="row"> <div class="row">
<div class="col s12"> <div class="col s12">
......
{% load i18n %}
<div class="card">
<div class="card-content">
<div class="card-title">{% trans "Legend" %}</div>
<div class="row">
<div class="col s12 m12 l4">
<h6>{% trans "General" %}</h6>
<ul class="collection">
<li class="collection-item chip-height">
<strong>(a)</strong> {% trans "Absences" %}
<span class="chip secondary-color white-text right">0</span>
</li>
<li class="collection-item chip-height">
<strong>(u)</strong> {% trans "Unexcused absences" %}
<span class="chip red white-text right">0</span>
</li>
<li class="collection-item chip-height">
<strong>(e)</strong> {% trans "Excused absences" %}
<span class="chip green white-text right">0</span>
</li>
</ul>
</div>
{% if excuse_types %}
<div class="col s12 m12 l4">
<h6>{% trans "Excuse types" %}</h6>
<ul class="collection">
{% for excuse_type in excuse_types %}
<li class="collection-item chip-height">
<strong>({{ excuse_type.short_name }})</strong> {{ excuse_type.name }}
<span class="chip grey white-text right">0</span>
</li>
{% endfor %}
</ul>
</div>
{% endif %}
{% if extra_marks %}
<div class="col s12 m12 l4">
<h6>{% trans "Extra marks" %}</h6>
<ul class="collection">
{% for extra_mark in extra_marks %}
<li class="collection-item chip-height">
<strong>{{ extra_mark.short_name }}</strong> {{ extra_mark.name }}
<span class="chip grey white-text right">0</span>
</li>
{% endfor %}
</ul>
</div>
{% endif %}
</div>
</div>
</div>
{% load data_helpers time_helpers i18n %}
{% if not persons %}
<div class="alert primary">
<div>
<i class="material-icons left">warning</i>
{% blocktrans %}No students available.{% endblocktrans %}
</div>
</div>
{% else %}
<table class="highlight responsive-table">
<thead>
<tr class="hide-on-med-and-down">
<th rowspan="2">{% trans "Name" %}</th>
<th rowspan="2">{% trans "Primary group" %}</th>
<th colspan="{{ excuse_types.count|add:3 }}">{% trans "Absences" %}</th>
<th rowspan="2">{% trans "Tardiness" %}</th>
{% if extra_marks %}
<th colspan="{{ extra_marks.count }}">{% trans "Extra marks" %}</th>
{% endif %}
<th rowspan="2"></th>
</tr>
<tr class="hide-on-large-only">
<th class="truncate">{% trans "Name" %}</th>
<th class="truncate">{% trans "Primary group" %}</th>
<th class="truncate chip-height">{% trans "Absences" %}</th>
<th class="chip-height">{% trans "(e)" %}</th>
{% for excuse_type in excuse_types %}
<th class="chip-height">
({{ excuse_type.short_name }})
</th>
{% endfor %}
<th class="chip-height">{% trans "(u)" %}</th>
<th class="truncate chip-height">{% trans "Tardiness" %}</th>
{% for extra_mark in extra_marks %}
<th class="chip-height">
{{ extra_mark.short_name }}
</th>
{% endfor %}
<th rowspan="2"></th>
</tr>
<tr class="hide-on-med-and-down">
<th>{% trans "Sum" %}</th>
<th>{% trans "(e)" %}</th>
{% for excuse_type in excuse_types %}
<th>
({{ excuse_type.short_name }})
</th>
{% endfor %}
<th>{% trans "(u)" %}</th>
{% for extra_mark in extra_marks %}
<th>
{{ extra_mark.short_name }}
</th>
{% endfor %}
</tr>
</thead>
{% for person in persons %}
<tr>
<td>
<a href="{% url "overview_person" person.pk %}">
{{ person }}
</a>
</td>
<td>
{% firstof person.primary_group "–" %}
</td>
<td>
<span class="chip secondary-color white-text" title="{% trans "Absences" %}">
{{ person.absences_count }}
</span>
</td>
<td class="green-text">
<span class="chip green white-text" title="{% trans "Excused" %}">
{{ person.excused }}
</span>
</td>
{% for excuse_type in excuse_types %}
<td>
<span class="chip grey white-text" title="{{ excuse_type.name }}">
{{ person|get_dict:excuse_type.count_label }}
</span>
</td>
{% endfor %}
<td class="red-text">
<span class="chip red white-text" title="{% trans "Unexcused" %}">
{{ person.unexcused }}
</span>
</td>
<td>
<span class="chip orange white-text" title="{% trans "Tardiness" %}">
{% firstof person.tardiness|to_time|time:"H\h i\m" "–" %}
</span>
<span class="chip orange white-text" title="{% trans "Count of tardiness" %}">{{ person.tardiness_count }} &times;</span>
</td>
{% for extra_mark in extra_marks %}
<td>
<span class="chip grey white-text" title="{{ extra_mark.name }}">
{{ person|get_dict:extra_mark.count_label }}
</span>
</td>
{% endfor %}
<td>
<a class="btn primary waves-effect waves-light" href="{% url "overview_person" person.pk %}">
<i class="material-icons left">insert_chart</i>
<span class="hide-on-med-and-down"> {% trans "Show more details" %}</span>
<span class="hide-on-large-only">{% trans "Details" %}</span>
</a>
</td>
</tr>
{% endfor %}
{% endif %}
</table>
...@@ -27,6 +27,7 @@ urlpatterns = [ ...@@ -27,6 +27,7 @@ urlpatterns = [
"print/group/<int:id_>", views.full_register_group, name="full_register_group" "print/group/<int:id_>", views.full_register_group, name="full_register_group"
), ),
path("groups/", views.my_groups, name="my_groups"), path("groups/", views.my_groups, name="my_groups"),
path("groups/<int:pk>/", views.StudentsList.as_view(), name="students_list"),
path("persons/", views.my_students, name="my_students"), path("persons/", views.my_students, name="my_students"),
path("persons/<int:id_>/", views.overview_person, name="overview_person"), path("persons/<int:id_>/", views.overview_person, name="overview_person"),
path("me/", views.overview_person, name="overview_me"), path("me/", views.overview_person, name="overview_me"),
......
...@@ -436,63 +436,18 @@ def full_register_group(request: HttpRequest, id_: int) -> HttpResponse: ...@@ -436,63 +436,18 @@ def full_register_group(request: HttpRequest, id_: int) -> HttpResponse:
(lesson_period, documentations, notes, substitution) (lesson_period, documentations, notes, substitution)
) )
persons = ( persons = Person.objects.prefetch_related(
Person.objects.prefetch_related( "personal_notes",
"personal_notes", "personal_notes__excuse_type",
"personal_notes__excuse_type", "personal_notes__extra_marks",
"personal_notes__extra_marks", "personal_notes__lesson_period__lesson__subject",
"personal_notes__lesson_period__lesson__subject", "personal_notes__lesson_period__substitutions",
"personal_notes__lesson_period__substitutions", "personal_notes__lesson_period__substitutions__subject",
"personal_notes__lesson_period__substitutions__subject", "personal_notes__lesson_period__substitutions__teachers",
"personal_notes__lesson_period__substitutions__teachers", "personal_notes__lesson_period__lesson__teachers",
"personal_notes__lesson_period__lesson__teachers", "personal_notes__lesson_period__period",
"personal_notes__lesson_period__period",
)
.filter(
personal_notes__groups_of_person=group,
personal_notes__lesson_period__lesson__validity__school_term=current_school_term,
)
.annotate(
absences_count=Count(
"personal_notes__absent",
filter=Q(
personal_notes__absent=True,
personal_notes__lesson_period__lesson__validity__school_term=current_school_term,
),
),
excused=Count(
"personal_notes__absent",
filter=Q(
personal_notes__absent=True,
personal_notes__excused=True,
personal_notes__excuse_type__isnull=True,
personal_notes__lesson_period__lesson__validity__school_term=current_school_term,
),
),
unexcused=Count(
"personal_notes__absent",
filter=Q(
personal_notes__absent=True,
personal_notes__excused=False,
personal_notes__lesson_period__lesson__validity__school_term=current_school_term,
),
),
tardiness=Sum("personal_notes__late"),
)
) )
persons = group.generate_person_list_with_class_register_statistics(persons)
for extra_mark in ExtraMark.objects.all():
persons = persons.annotate(
**{
extra_mark.count_label: Count(
"personal_notes",
filter=Q(
personal_notes__extra_marks=extra_mark,
personal_notes__lesson_period__lesson__validity__school_term=current_school_term,
),
)
}
)
for excuse_type in ExcuseType.objects.all(): for excuse_type in ExcuseType.objects.all():
persons = persons.annotate( persons = persons.annotate(
...@@ -535,19 +490,52 @@ def full_register_group(request: HttpRequest, id_: int) -> HttpResponse: ...@@ -535,19 +490,52 @@ def full_register_group(request: HttpRequest, id_: int) -> HttpResponse:
@permission_required("alsijil.view_my_students") @permission_required("alsijil.view_my_students")
def my_students(request: HttpRequest) -> HttpResponse: def my_students(request: HttpRequest) -> HttpResponse:
context = {} context = {}
relevant_groups = request.user.person.get_owner_groups_with_lessons() relevant_groups = (
persons = Person.objects.filter(member_of__in=relevant_groups) request.user.person.get_owner_groups_with_lessons()
context["persons"] = persons .filter(members__isnull=False)
.prefetch_related("members")
.distinct()
)
relevant_groups = sorted(
relevant_groups, key=lambda g: g.name if g.parent_groups else "0"
)
new_groups = []
for group in relevant_groups:
persons = group.generate_person_list_with_class_register_statistics()
new_groups.append((group, persons))
context["groups"] = new_groups
context["excuse_types"] = ExcuseType.objects.all()
context["extra_marks"] = ExtraMark.objects.all()
return render(request, "alsijil/class_register/persons.html", context) return render(request, "alsijil/class_register/persons.html", context)
@permission_required("alsijil.view_my_groups",) @permission_required("alsijil.view_my_groups",)
def my_groups(request: HttpRequest) -> HttpResponse: def my_groups(request: HttpRequest) -> HttpResponse:
context = {} context = {}
context["groups"] = request.user.person.get_owner_groups_with_lessons() context["groups"] = request.user.person.get_owner_groups_with_lessons().annotate(
students_count=Count("members")
)
return render(request, "alsijil/class_register/groups.html", context) return render(request, "alsijil/class_register/groups.html", context)
class StudentsList(PermissionRequiredMixin, DetailView):
model = Group
template_name = "alsijil/class_register/students_list.html"
permission_required = "alsijil.view_students_list"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["group"] = self.object
context[
"persons"
] = self.object.generate_person_list_with_class_register_statistics()
context["extra_marks"] = ExtraMark.objects.all()
context["excuse_types"] = ExcuseType.objects.all()
return context
@permission_required( @permission_required(
"alsijil.view_person_overview", "alsijil.view_person_overview",
fn=objectgetter_optional(Person, "request.user.person", True), fn=objectgetter_optional(Person, "request.user.person", True),
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment