Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
A
AlekSIS-App-Alsijil
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Container Registry
Model registry
Operate
Environments
Monitor
Incidents
Service Desk
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Terms and privacy
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
AlekSIS®
Official
AlekSIS-App-Alsijil
Commits
6c29d76d
Verified
Commit
6c29d76d
authored
4 years ago
by
Jonathan Weth
Browse files
Options
Downloads
Patches
Plain Diff
Use select_related and prefetch_related everywhere and optimize query count
parent
e223b95d
No related branches found
No related tags found
1 merge request
!90
Performance optimizations
Pipeline
#3623
passed
4 years ago
Stage: test
Stage: build
Changes
2
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
aleksis/apps/alsijil/model_extensions.py
+6
-7
6 additions, 7 deletions
aleksis/apps/alsijil/model_extensions.py
aleksis/apps/alsijil/views.py
+104
-57
104 additions, 57 deletions
aleksis/apps/alsijil/views.py
with
110 additions
and
64 deletions
aleksis/apps/alsijil/model_extensions.py
+
6
−
7
View file @
6c29d76d
...
@@ -119,7 +119,7 @@ def get_personal_notes(self, persons: QuerySet, wanted_week: CalendarWeek):
...
@@ -119,7 +119,7 @@ def get_personal_notes(self, persons: QuerySet, wanted_week: CalendarWeek):
for
personal_note
in
new_personal_notes
:
for
personal_note
in
new_personal_notes
:
personal_note
.
groups_of_person
.
set
(
personal_note
.
person
.
member_of
.
all
())
personal_note
.
groups_of_person
.
set
(
personal_note
.
person
.
member_of
.
all
())
return
PersonalNote
.
objects
.
select_related
(
"
person
"
).
filter
(
return
PersonalNote
.
objects
.
filter
(
lesson_period
=
self
,
lesson_period
=
self
,
week
=
wanted_week
.
week
,
week
=
wanted_week
.
week
,
year
=
wanted_week
.
year
,
year
=
wanted_week
.
year
,
...
@@ -165,12 +165,11 @@ def get_lesson_documentation(
...
@@ -165,12 +165,11 @@ def get_lesson_documentation(
"""
Get lesson documentation object for this lesson.
"""
"""
Get lesson documentation object for this lesson.
"""
if
not
week
:
if
not
week
:
week
=
self
.
week
week
=
self
.
week
try
:
# Use all to make effect of prefetched data
return
LessonDocumentation
.
objects
.
get
(
for
documentation
in
self
.
documentations
.
all
():
lesson_period
=
self
,
week
=
week
.
week
,
year
=
week
.
year
if
documentation
.
week
==
week
.
week
and
documentation
.
year
==
week
.
year
:
)
return
documentation
except
LessonDocumentation
.
DoesNotExist
:
return
None
return
None
@LessonPeriod.method
@LessonPeriod.method
...
...
This diff is collapsed.
Click to expand it.
aleksis/apps/alsijil/views.py
+
104
−
57
View file @
6c29d76d
...
@@ -2,7 +2,7 @@ from datetime import date, datetime, timedelta
...
@@ -2,7 +2,7 @@ from datetime import date, datetime, timedelta
from
typing
import
Optional
from
typing
import
Optional
from
django.core.exceptions
import
PermissionDenied
from
django.core.exceptions
import
PermissionDenied
from
django.db.models
import
Count
,
Exists
,
OuterRef
,
Q
,
Subquery
,
Sum
from
django.db.models
import
Count
,
Exists
,
OuterRef
,
Prefetch
,
Q
,
Subquery
,
Sum
from
django.http
import
Http404
,
HttpRequest
,
HttpResponse
,
HttpResponseNotFound
from
django.http
import
Http404
,
HttpRequest
,
HttpResponse
,
HttpResponseNotFound
from
django.shortcuts
import
get_object_or_404
,
redirect
,
render
from
django.shortcuts
import
get_object_or_404
,
redirect
,
render
from
django.urls
import
reverse
,
reverse_lazy
from
django.urls
import
reverse
,
reverse_lazy
...
@@ -16,7 +16,7 @@ from reversion.views import RevisionMixin
...
@@ -16,7 +16,7 @@ from reversion.views import RevisionMixin
from
rules.contrib.views
import
PermissionRequiredMixin
,
permission_required
from
rules.contrib.views
import
PermissionRequiredMixin
,
permission_required
from
aleksis.apps.chronos.managers
import
TimetableType
from
aleksis.apps.chronos.managers
import
TimetableType
from
aleksis.apps.chronos.models
import
LessonPeriod
,
TimePeriod
from
aleksis.apps.chronos.models
import
LessonPeriod
,
LessonSubstitution
,
TimePeriod
from
aleksis.apps.chronos.util.chronos_helpers
import
get_el_by_pk
from
aleksis.apps.chronos.util.chronos_helpers
import
get_el_by_pk
from
aleksis.apps.chronos.util.date
import
get_weeks_for_year
,
week_weekday_to_date
from
aleksis.apps.chronos.util.date
import
get_weeks_for_year
,
week_weekday_to_date
from
aleksis.core.mixins
import
AdvancedCreateView
,
AdvancedDeleteView
,
AdvancedEditView
from
aleksis.core.mixins
import
AdvancedCreateView
,
AdvancedDeleteView
,
AdvancedEditView
...
@@ -179,17 +179,9 @@ def week_view(
...
@@ -179,17 +179,9 @@ def week_view(
instance
=
get_instance_by_pk
(
request
,
year
,
week
,
type_
,
id_
)
instance
=
get_instance_by_pk
(
request
,
year
,
week
,
type_
,
id_
)
lesson_periods
=
LessonPeriod
.
objects
.
in_week
(
wanted_week
).
annotate
(
lesson_periods
=
LessonPeriod
.
objects
.
in_week
(
wanted_week
)
has_documentation
=
Exists
(
LessonDocumentation
.
objects
.
filter
(
~
Q
(
topic__exact
=
""
),
lesson_period
=
OuterRef
(
"
pk
"
),
week
=
wanted_week
.
week
,
year
=
wanted_week
.
year
,
)
)
)
lesson_periods_query_exists
=
True
if
type_
and
id_
:
if
type_
and
id_
:
if
isinstance
(
instance
,
HttpResponseNotFound
):
if
isinstance
(
instance
,
HttpResponseNotFound
):
return
HttpResponseNotFound
()
return
HttpResponseNotFound
()
...
@@ -204,6 +196,7 @@ def week_view(
...
@@ -204,6 +196,7 @@ def week_view(
else
:
else
:
lesson_periods
=
lesson_periods
.
filter_participant
(
request
.
user
.
person
)
lesson_periods
=
lesson_periods
.
filter_participant
(
request
.
user
.
person
)
else
:
else
:
lesson_periods_query_exists
=
False
lesson_periods
=
None
lesson_periods
=
None
# Add a form to filter the view
# Add a form to filter the view
...
@@ -231,10 +224,38 @@ def week_view(
...
@@ -231,10 +224,38 @@ def week_view(
else
:
else
:
group
=
None
group
=
None
if
lesson_periods
:
extra_marks
=
ExtraMark
.
objects
.
all
()
# Aggregate all personal notes for this group and week
if
lesson_periods_query_exists
:
lesson_periods_pk
=
list
(
lesson_periods
.
values_list
(
"
pk
"
,
flat
=
True
))
lesson_periods_pk
=
list
(
lesson_periods
.
values_list
(
"
pk
"
,
flat
=
True
))
lesson_periods
=
(
LessonPeriod
.
objects
.
prefetch_related
(
Prefetch
(
"
documentations
"
,
queryset
=
LessonDocumentation
.
objects
.
filter
(
week
=
wanted_week
.
week
,
year
=
wanted_week
.
year
),
)
)
.
filter
(
pk__in
=
lesson_periods_pk
)
.
annotate_week
(
wanted_week
)
.
annotate
(
has_documentation
=
Exists
(
LessonDocumentation
.
objects
.
filter
(
~
Q
(
topic__exact
=
""
),
lesson_period
=
OuterRef
(
"
pk
"
),
week
=
wanted_week
.
week
,
year
=
wanted_week
.
year
,
)
)
)
.
order_by
(
"
period__weekday
"
,
"
period__period
"
)
)
else
:
lesson_periods_pk
=
[]
if
lesson_periods_pk
:
# Aggregate all personal notes for this group and week
persons_qs
=
Person
.
objects
.
filter
(
is_active
=
True
)
persons_qs
=
Person
.
objects
.
filter
(
is_active
=
True
)
if
not
request
.
user
.
has_perm
(
"
alsijil.view_week_personalnote
"
,
instance
):
if
not
request
.
user
.
has_perm
(
"
alsijil.view_week_personalnote
"
,
instance
):
...
@@ -285,7 +306,7 @@ def week_view(
...
@@ -285,7 +306,7 @@ def week_view(
)
)
)
)
for
extra_mark
in
E
xtra
M
ark
.
objects
.
all
()
:
for
extra_mark
in
e
xtra
_m
ark
s
:
persons_qs
=
persons_qs
.
annotate
(
persons_qs
=
persons_qs
.
annotate
(
**
{
**
{
extra_mark
.
count_label
:
Count
(
extra_mark
.
count_label
:
Count
(
...
@@ -306,22 +327,19 @@ def week_view(
...
@@ -306,22 +327,19 @@ def week_view(
persons
.
append
(
persons
.
append
(
{
{
"
person
"
:
person
,
"
person
"
:
person
,
"
personal_notes
"
:
person
.
personal_notes
.
filter
(
"
personal_notes
"
:
list
(
week
=
wanted_week
.
week
,
person
.
personal_notes
.
filter
(
year
=
wanted_week
.
year
,
week
=
wanted_week
.
week
,
lesson_period__in
=
lesson_periods_pk
,
year
=
wanted_week
.
year
,
lesson_period__in
=
lesson_periods_pk
,
).
prefetch_related
(
"
lesson_period__substitutions__subject
"
)
),
),
}
}
)
)
else
:
else
:
persons
=
None
persons
=
None
# Resort lesson periods manually because an union queryset doesn't support order_by
context
[
"
extra_marks
"
]
=
extra_marks
lesson_periods
=
sorted
(
lesson_periods
,
key
=
lambda
x
:
(
x
.
period
.
weekday
,
x
.
period
.
period
)
)
context
[
"
extra_marks
"
]
=
ExtraMark
.
objects
.
all
()
context
[
"
week
"
]
=
wanted_week
context
[
"
week
"
]
=
wanted_week
context
[
"
weeks
"
]
=
get_weeks_for_year
(
year
=
wanted_week
.
year
)
context
[
"
weeks
"
]
=
get_weeks_for_year
(
year
=
wanted_week
.
year
)
context
[
"
lesson_periods
"
]
=
lesson_periods
context
[
"
lesson_periods
"
]
=
lesson_periods
...
@@ -369,7 +387,14 @@ def full_register_group(request: HttpRequest, id_: int) -> HttpResponse:
...
@@ -369,7 +387,14 @@ def full_register_group(request: HttpRequest, id_: int) -> HttpResponse:
LessonPeriod
.
objects
.
filter_group
(
group
)
LessonPeriod
.
objects
.
filter_group
(
group
)
.
filter
(
lesson__validity__school_term
=
current_school_term
)
.
filter
(
lesson__validity__school_term
=
current_school_term
)
.
distinct
()
.
distinct
()
.
prefetch_related
(
"
documentations
"
,
"
personal_notes
"
)
.
prefetch_related
(
"
documentations
"
,
"
personal_notes
"
,
"
personal_notes__excuse_type
"
,
"
personal_notes__extra_marks
"
,
"
personal_notes__person
"
,
"
personal_notes__groups_of_person
"
,
)
)
)
weeks
=
CalendarWeek
.
weeks_within
(
weeks
=
CalendarWeek
.
weeks_within
(
...
@@ -404,35 +429,49 @@ def full_register_group(request: HttpRequest, id_: int) -> HttpResponse:
...
@@ -404,35 +429,49 @@ def full_register_group(request: HttpRequest, id_: int) -> HttpResponse:
(
lesson_period
,
documentations
,
notes
,
substitution
)
(
lesson_period
,
documentations
,
notes
,
substitution
)
)
)
persons
=
Person
.
objects
.
filter
(
persons
=
(
personal_notes__groups_of_person
=
group
,
Person
.
objects
.
prefetch_related
(
personal_notes__lesson_period__lesson__validity__school_term
=
current_school_term
,
"
personal_notes
"
,
).
annotate
(
"
personal_notes__excuse_type
"
,
absences_count
=
Count
(
"
personal_notes__extra_marks
"
,
"
personal_notes__absent
"
,
"
personal_notes__lesson_period__lesson__subject
"
,
filter
=
Q
(
"
personal_notes__lesson_period__substitutions
"
,
personal_notes__absent
=
True
,
"
personal_notes__lesson_period__substitutions__subject
"
,
personal_notes__lesson_period__lesson__validity__school_term
=
current_school_term
,
"
personal_notes__lesson_period__substitutions__teachers
"
,
"
personal_notes__lesson_period__lesson__teachers
"
,
"
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
(
excused
=
Count
(
"
personal_notes__absent
"
,
"
personal_notes__absent
"
,
filter
=
Q
(
filter
=
Q
(
personal_notes__absent
=
True
,
personal_notes__
absent
=
True
,
personal_notes__
excused
=
True
,
personal_notes__excuse
d
=
True
,
personal_notes__excuse
_type__isnull
=
True
,
personal_notes__
excuse_type__isnull
=
True
,
personal_notes__
lesson_period__lesson__validity__school_term
=
current_school_term
,
personal_notes__lesson_period__lesson__validity__school_term
=
current_school_term
,
)
,
),
),
),
unexcused
=
Count
(
unexcused
=
Count
(
"
personal_notes__absent
"
,
"
personal_notes__absent
"
,
filter
=
Q
(
filter
=
Q
(
personal_notes__absent
=
True
,
personal_notes__
absent
=
Tru
e
,
personal_notes__
excused
=
Fals
e
,
personal_notes__
excused
=
False
,
personal_notes__
lesson_period__lesson__validity__school_term
=
current_school_term
,
personal_notes__lesson_period__lesson__validity__school_term
=
current_school_term
,
)
,
),
),
),
tardiness
=
Sum
(
"
personal_notes__late
"
),
tardiness
=
Sum
(
"
personal_notes__late
"
),
)
)
)
for
extra_mark
in
ExtraMark
.
objects
.
all
():
for
extra_mark
in
ExtraMark
.
objects
.
all
():
...
@@ -578,7 +617,11 @@ def overview_person(request: HttpRequest, id_: Optional[int] = None) -> HttpResp
...
@@ -578,7 +617,11 @@ def overview_person(request: HttpRequest, id_: Optional[int] = None) -> HttpResp
person
.
refresh_from_db
()
person
.
refresh_from_db
()
allowed_personal_notes
=
person
.
personal_notes
.
all
()
allowed_personal_notes
=
person
.
personal_notes
.
all
().
prefetch_related
(
"
lesson_period__lesson__groups
"
,
"
lesson_period__lesson__teachers
"
,
"
lesson_period__substitutions
"
,
)
if
not
request
.
user
.
has_perm
(
"
alsijil.view_person_overview_personalnote
"
,
person
):
if
not
request
.
user
.
has_perm
(
"
alsijil.view_person_overview_personalnote
"
,
person
):
print
(
"
has
"
)
print
(
"
has
"
)
...
@@ -602,6 +645,8 @@ def overview_person(request: HttpRequest, id_: Optional[int] = None) -> HttpResp
...
@@ -602,6 +645,8 @@ def overview_person(request: HttpRequest, id_: Optional[int] = None) -> HttpResp
context
[
"
personal_notes
"
]
=
personal_notes
context
[
"
personal_notes
"
]
=
personal_notes
context
[
"
excuse_types
"
]
=
ExcuseType
.
objects
.
all
()
context
[
"
excuse_types
"
]
=
ExcuseType
.
objects
.
all
()
extra_marks
=
ExtraMark
.
objects
.
all
()
excuse_types
=
ExcuseType
.
objects
.
all
()
if
request
.
user
.
has_perm
(
"
alsijil.view_person_statistics_personalnote
"
,
person
):
if
request
.
user
.
has_perm
(
"
alsijil.view_person_statistics_personalnote
"
,
person
):
school_terms
=
SchoolTerm
.
objects
.
all
().
order_by
(
"
-date_start
"
)
school_terms
=
SchoolTerm
.
objects
.
all
().
order_by
(
"
-date_start
"
)
stats
=
[]
stats
=
[]
...
@@ -631,14 +676,14 @@ def overview_person(request: HttpRequest, id_: Optional[int] = None) -> HttpResp
...
@@ -631,14 +676,14 @@ def overview_person(request: HttpRequest, id_: Optional[int] = None) -> HttpResp
)
)
stat
.
update
(
personal_notes
.
aggregate
(
tardiness
=
Sum
(
"
late
"
)))
stat
.
update
(
personal_notes
.
aggregate
(
tardiness
=
Sum
(
"
late
"
)))
for
extra_mark
in
E
xtra
M
ark
.
objects
.
all
()
:
for
extra_mark
in
e
xtra
_m
ark
s
:
stat
.
update
(
stat
.
update
(
personal_notes
.
filter
(
extra_marks
=
extra_mark
).
aggregate
(
personal_notes
.
filter
(
extra_marks
=
extra_mark
).
aggregate
(
**
{
extra_mark
.
count_label
:
Count
(
"
pk
"
)}
**
{
extra_mark
.
count_label
:
Count
(
"
pk
"
)}
)
)
)
)
for
excuse_type
in
E
xcuse
T
ype
.
objects
.
all
()
:
for
excuse_type
in
e
xcuse
_t
ype
s
:
stat
.
update
(
stat
.
update
(
personal_notes
.
filter
(
personal_notes
.
filter
(
absent
=
True
,
excuse_type
=
excuse_type
absent
=
True
,
excuse_type
=
excuse_type
...
@@ -647,8 +692,10 @@ def overview_person(request: HttpRequest, id_: Optional[int] = None) -> HttpResp
...
@@ -647,8 +692,10 @@ def overview_person(request: HttpRequest, id_: Optional[int] = None) -> HttpResp
stats
.
append
((
school_term
,
stat
))
stats
.
append
((
school_term
,
stat
))
context
[
"
stats
"
]
=
stats
context
[
"
stats
"
]
=
stats
context
[
"
excuse_types
"
]
=
ExcuseType
.
objects
.
all
()
context
[
"
extra_marks
"
]
=
ExtraMark
.
objects
.
all
()
context
[
"
excuse_types
"
]
=
excuse_types
context
[
"
extra_marks
"
]
=
extra_marks
return
render
(
request
,
"
alsijil/class_register/person.html
"
,
context
)
return
render
(
request
,
"
alsijil/class_register/person.html
"
,
context
)
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment