Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
dbchiro
dbchiroweb
Commits
64590231
Commit
64590231
authored
Apr 14, 2021
by
hypsug0
Browse files
fix: widely improve perfs using select|prefetch_related (3x to 10x faster), to be continued
parent
9996aceb
Changes
13
Hide whitespace changes
Inline
Side-by-side
core/static/css/app.css
View file @
64590231
...
...
@@ -95,7 +95,7 @@ header h1 {
color
:
#fff
;
height
:
65px
;
box-shadow
:
0
1px
1px
rgba
(
0
,
0
,
0
,
0.05
);
background-color
:
#473030
;
}
.page-header
h1
{
...
...
core/static/js/app.js
View file @
64590231
...
...
@@ -594,7 +594,7 @@ const placeSearchBlock = () => {
$
(
'
#searchForm
'
).
on
(
'
click change
'
,
'
input, select
'
,
function
()
{
clearTimeout
(
debounce
)
debounce
=
setTimeout
(
showValues
,
20
00
)
debounce
=
setTimeout
(
showValues
,
5
00
)
})
showValues
()
...
...
@@ -990,7 +990,7 @@ const sightingSearchBlock = () => {
var
debounce
=
null
$
(
'
#searchForm
'
).
on
(
'
click change
'
,
'
input, select
'
,
function
()
{
clearTimeout
(
debounce
)
debounce
=
setTimeout
(
showValues
,
20
00
)
debounce
=
setTimeout
(
showValues
,
5
00
)
})
showValues
()
...
...
management/study/views.py
View file @
64590231
...
...
@@ -4,6 +4,7 @@
from
django.contrib.auth.mixins
import
LoginRequiredMixin
from
django.db.models
import
Prefetch
from
django.urls
import
reverse_lazy
from
django.utils.translation
import
ugettext_lazy
as
_
from
django.views.generic
import
DetailView
...
...
@@ -89,7 +90,18 @@ class StudyList(LoginRequiredMixin, SingleTableView):
class
StudyDetail
(
LoginRequiredMixin
,
DetailView
):
queryset
=
Study
.
objects
.
select_related
()
queryset
=
(
Study
.
objects
.
select_related
(
"project_manager"
)
.
select_related
(
"created_by"
)
.
select_related
(
"updated_by"
)
.
prefetch_related
(
"sessions"
)
.
prefetch_related
(
Prefetch
(
"sessions__sighting_set"
))
.
prefetch_related
(
Prefetch
(
"sessions__place"
))
.
prefetch_related
(
Prefetch
(
"sessions__contact"
))
.
prefetch_related
(
Prefetch
(
"sessions__sighting_set__codesp"
))
.
prefetch_related
(
Prefetch
(
"sessions__main_observer"
))
.
prefetch_related
(
Prefetch
(
"sessions__other_observer"
))
)
template_name
=
"study_detail.html"
def
get_context_data
(
self
,
**
kwargs
):
...
...
management/tables.py
View file @
64590231
...
...
@@ -42,7 +42,9 @@ class StudyTable(tables.Table):
</div>
</div>
"""
LINK_NAME
=
'<a href="{% url "management:url_study_detail" record.pk %}" target="_blank" title="Voir">{{record.name}}'
actions
=
tables
.
TemplateColumn
(
ACTIONS
,
verbose_name
=
"Actions"
,
orderable
=
False
)
link_name
=
tables
.
TemplateColumn
(
LINK_NAME
,
verbose_name
=
"Nom"
,
orderable
=
True
)
class
Meta
:
model
=
Study
...
...
@@ -50,7 +52,7 @@ class StudyTable(tables.Table):
attrs
=
{
"class"
:
"table table-striped table-condensed"
}
fields
=
(
"actions"
,
"name"
,
"
link_
name"
,
"uuid"
,
"year"
,
"project_manager"
,
...
...
management/templates/study_detail.html
View file @
64590231
...
...
@@ -73,7 +73,10 @@
<div
class=
"list-group"
>
{% for s in object.sessions.all %}
<div
class=
"list-group-item"
>
<h4
class=
"list-group-item-heading"
>
{{s.place.name}} - {{s.date_start}} ({{s.contact.descr}})
<h4
class=
"list-group-item-heading"
>
<span
class=
"pull-right label label-default label-lg"
>
{{s.contact.descr}}
</span>
{{s.place.name}} - {{s.date_start}}
</h4>
<p
class=
"list-group-item-text"
>
<dl
class=
"dl-horizontal"
>
...
...
@@ -84,7 +87,11 @@
<dd>
<ul
class=
"list-unstyled"
>
{%for o in s.sighting_set.all %}
<li>
{{o.codesp.sci_name}} : {{o.total_count}} {{o.is_breeding}}
</li>
<li
class=
"{{o.codesp.sp_true|yesno:',text-muted'}}"
>
<strong>
{{o.codesp.common_name_fr}}
</strong>
(
<i>
{{o.codesp.sci_name}}
</i>
)
: {{o.total_count}}
{{o.is_breeding}}
</li>
{% endfor %}
</ul>
</dd>
...
...
management/urls.py
View file @
64590231
...
...
@@ -20,7 +20,7 @@ urlpatterns = [
path
(
"study/<int:pk>/delete"
,
StudyDelete
.
as_view
(),
name
=
"study_delete"
),
path
(
"study/list"
,
StudyList
.
as_view
(),
name
=
"study_list"
),
path
(
"study/list/<int:page>"
,
StudyList
.
as_view
(),
name
=
"url_study_list"
),
path
(
"study/
detail/
<int:pk>"
,
StudyDetail
.
as_view
(),
name
=
"url_study_detail"
),
path
(
"study/<int:pk>
/detail
"
,
StudyDetail
.
as_view
(),
name
=
"url_study_detail"
),
path
(
"api/v1/study/<int:pk>/observations"
,
StudySightings
.
as_view
(),
name
=
"api_study_sightings"
),
...
...
sights/mixins.py
View file @
64590231
...
...
@@ -67,15 +67,17 @@ class PlaceViewAuthMixin(LoginRequiredMixin):
def
dispatch
(
self
,
request
,
*
args
,
**
kwargs
):
self
.
obj
=
self
.
get_object
()
if
not
request
.
user
.
is_authenticated
:
logger
.
debug
(
f
"request.user
{
request
.
user
}
{
dir
(
request
.
user
)
}
"
)
logger
.
debug
(
f
"self
{
self
}
{
dir
(
self
)
}
"
)
user
=
request
.
user
if
not
user
.
is_authenticated
:
return
redirect
(
f
"
{
reverse
(
'auth_login'
)
}
?next=
{
request
.
path
}
"
)
else
:
loggeduser
=
get_user_model
().
objects
.
get
(
id
=
request
.
user
.
id
)
if
(
logged
user
.
edit_all_data
or
self
.
obj
.
created_by
==
logged
user
or
(
self
.
obj
.
is_hidden
and
logged
user
in
self
.
obj
.
authorized_user
.
all
())
or
(
logged
user
.
is_resp
and
self
.
obj
.
territory
in
logged
user
.
resp_territory
.
all
())
user
.
edit_all_data
or
self
.
obj
.
created_by
==
user
or
(
self
.
obj
.
is_hidden
and
user
in
self
.
obj
.
authorized_user
.
all
())
or
(
user
.
is_resp
and
self
.
obj
.
territory
in
user
.
resp_territory
.
all
())
or
not
self
.
obj
.
is_hidden
):
logger
.
debug
(
"access granted"
)
...
...
@@ -450,13 +452,7 @@ class PlaceFilteringMixin:
"""Mixin used for Place lists filtering"""
def
get_queryset
(
self
,
*
args
,
**
kwargs
):
qs
=
(
Place
.
objects
.
select_related
(
"municipality"
)
.
select_related
(
"metaplace"
)
.
select_related
(
"creator"
)
.
select_related
(
"type"
)
.
select_related
(
"territory"
)
)
qs
=
super
(
PlaceFilteringMixin
,
self
).
get_queryset
()
municipality
=
self
.
request
.
query_params
.
get
(
"municipality"
,
None
)
name
=
self
.
request
.
query_params
.
get
(
"name"
,
None
)
...
...
@@ -470,8 +466,6 @@ class PlaceFilteringMixin:
managed
=
self
.
request
.
query_params
.
get
(
"managed"
,
None
)
territory
=
self
.
request
.
query_params
.
get
(
"territory"
,
None
)
qs
=
Place
.
objects
.
order_by
(
"-timestamp_create"
)
qs
=
(
qs
.
filter
(
Q
(
municipality__name__icontains
=
municipality
)
...
...
@@ -519,9 +513,6 @@ class PlaceFilteringMixin:
)
qs
=
qs
.
filter
(
territory__id
=
territory
)
if
territory
is
not
None
else
qs
qs
=
qs
.
select_related
(
"created_by"
,
"type"
).
prefetch_related
(
Prefetch
(
"municipality"
,
queryset
=
Municipality
.
objects
.
only
(
"name"
,
"code"
))
)
logger
.
debug
(
f
"Q
{
qs
}
"
)
return
qs
...
...
@@ -530,9 +521,7 @@ class PlaceListPermissionsMixin:
def
get_queryset
(
self
,
*
args
,
**
kwargs
):
qs
=
super
(
PlaceListPermissionsMixin
,
self
).
get_queryset
()
logged_user
=
self
.
request
.
user
user
=
get_user_model
().
objects
.
get
(
id
=
logged_user
.
id
)
user
=
self
.
request
.
user
if
user
.
access_all_data
or
user
.
edit_all_data
or
user
.
is_superuser
:
qs
=
qs
...
...
@@ -550,7 +539,6 @@ class PlaceListPermissionsMixin:
.
distinct
()
.
order_by
(
"-timestamp_update"
)
)
logger
.
debug
(
qs
.
query
)
return
qs
...
...
sights/models.py
View file @
64590231
...
...
@@ -1016,7 +1016,7 @@ class Sighting(models.Model):
)
def
__str__
(
self
):
return
"%s ∙ %s
∙ %s"
%
(
self
.
session
,
self
.
codesp
,
self
.
total_count
)
return
"%s ∙ %s
"
%
(
self
.
codesp
,
self
.
total_count
)
def
get_absolute_url
(
self
):
return
reverse
(
"sights:sighting_detail"
,
kwargs
=
{
"pk"
:
self
.
id_sighting
})
...
...
sights/observation/api.py
View file @
64590231
...
...
@@ -28,20 +28,28 @@ class GeoJSONSighting(
SightingFilteredListWithPermissions
,
ListAPIView
,
):
queryset
=
Sighting
.
objects
.
all
()
queryset
=
(
Sighting
.
objects
.
select_related
(
"created_by"
)
.
select_related
(
"updated_by"
)
.
select_related
(
"observer"
)
.
select_related
(
"session"
)
.
select_related
(
"codesp"
)
.
prefetch_related
(
"session__place"
)
.
prefetch_related
(
"session__place__municipality"
)
.
prefetch_related
(
"session__place__territory"
)
.
prefetch_related
(
"session__place__type"
)
.
prefetch_related
(
"session__contact"
)
.
prefetch_related
(
"session__main_observer"
)
.
prefetch_related
(
"session__other_observer"
)
.
prefetch_related
(
"session__study"
)
.
all
()
)
serializer_class
=
GeoSightingSerializer
pagination_class
=
LargeGeoJsonPageNumberPagination
def
get_queryset
(
self
,
*
args
,
**
kwargs
):
qs
=
super
().
get_queryset
()
qs
=
qs
.
select_related
(
"created_by"
,
"codesp"
,
"session"
,).
prefetch_related
(
Prefetch
(
"session__contact"
),
Prefetch
(
"session__place"
),
Prefetch
(
"session__place__municipality"
),
Prefetch
(
"session__place__territory"
),
)
return
qs
.
distinct
().
order_by
(
"-timestamp_update"
)
...
...
@@ -56,6 +64,7 @@ class EditSighting(SightingListPermissionsMixin, ModelViewSet):
def
get_queryset
(
self
,
*
args
,
**
kwargs
):
qs
=
super
().
get_queryset
()
qs
=
qs
.
select_related
(
"countdetails"
)
if
self
.
action
in
(
"list"
,
"create"
):
session
=
self
.
kwargs
[
"session"
]
qs
=
qs
.
filter
(
session
=
session
)
...
...
sights/observation/serializers.py
View file @
64590231
...
...
@@ -99,7 +99,6 @@ class GeoSightingSerializer(serializers.GeoFeatureModelSerializer):
)
def
get_geom
(
self
,
sighting
):
logger
.
debug
(
f
"sighting
{
sighting
}
"
)
return
sighting
.
session
.
place
.
geom
...
...
sights/observation/views.py
View file @
64590231
...
...
@@ -6,7 +6,7 @@ from django.contrib import messages
from
django.contrib.auth
import
get_user_model
from
django.contrib.auth.mixins
import
LoginRequiredMixin
from
django.db
import
IntegrityError
from
django.db.models
import
Q
from
django.db.models
import
Prefetch
,
Q
from
django.http
import
HttpResponseRedirect
from
django.urls
import
reverse_lazy
from
django.utils.translation
import
ugettext_lazy
as
_
...
...
@@ -232,10 +232,23 @@ class SightingMyList(LoginRequiredMixin, ExportMixin, SingleTableView):
)
.
distinct
()
.
order_by
(
"-timestamp_update"
)
.
select_related
(
"created_by"
)
.
select_related
(
"updated_by"
)
.
select_related
(
"observer"
)
.
select_related
(
"session"
)
.
select_related
(
"codesp"
)
.
prefetch_related
(
"session__place"
)
.
prefetch_related
(
"session__place__municipality"
)
.
prefetch_related
(
"session__place__territory"
)
.
prefetch_related
(
"session__place__type"
)
.
prefetch_related
(
"session__contact"
)
.
prefetch_related
(
"session__main_observer"
)
.
prefetch_related
(
"session__other_observer"
)
.
prefetch_related
(
"session__study"
)
)
class
SightingUserList
(
AdvancedUserViewMixin
,
SingleTableView
):
class
SightingUserList
(
AdvancedUserViewMixin
,
ExportMixin
,
SingleTableView
):
table_class
=
SightingTable
template_name
=
"table.html"
table_pagination
=
{
"per_page"
:
25
}
...
...
@@ -271,10 +284,25 @@ class SightingUserList(AdvancedUserViewMixin, SingleTableView):
def
get_queryset
(
self
):
user
=
get_user_model
().
objects
.
get
(
id
=
self
.
kwargs
.
get
(
"pk"
))
loggeduser
=
get_user_model
().
objects
.
get
(
id
=
self
.
request
.
user
.
id
)
userlist
=
Sighting
.
objects
.
filter
(
Q
(
created_by
=
user
)
|
Q
(
observer
=
user
)
|
Q
(
session__other_observer__username__contains
=
user
.
username
)
userlist
=
(
Sighting
.
objects
.
filter
(
Q
(
created_by
=
user
)
|
Q
(
observer
=
user
)
|
Q
(
session__other_observer__username__contains
=
user
.
username
)
)
.
select_related
(
"created_by"
)
.
select_related
(
"updated_by"
)
.
select_related
(
"observer"
)
.
select_related
(
"session"
)
.
select_related
(
"codesp"
)
.
prefetch_related
(
"session__place"
)
.
prefetch_related
(
"session__place__municipality"
)
.
prefetch_related
(
"session__place__territory"
)
.
prefetch_related
(
"session__place__type"
)
.
prefetch_related
(
"session__contact"
)
.
prefetch_related
(
"session__main_observer"
)
.
prefetch_related
(
"session__other_observer"
)
.
prefetch_related
(
"session__study"
)
)
if
loggeduser
.
access_all_data
or
loggeduser
.
edit_all_data
:
return
userlist
.
distinct
().
order_by
(
"-timestamp_update"
)
...
...
sights/place/api.py
View file @
64590231
...
...
@@ -6,11 +6,24 @@ from rest_framework import generics
from
rest_framework_gis.filters
import
InBBoxFilter
from
sights.mixins
import
LargeGeoJsonPageNumberPagination
,
PlaceFilteredListWithPermissions
from
sights.models
import
Place
from
sights.place.serializers
import
CountModelMixin
,
PlaceSerializer
# Get an instance of a logger
logger
=
logging
.
getLogger
(
__name__
)
place_qs
=
(
(
Place
.
objects
.
select_related
(
"municipality"
)
.
select_related
(
"metaplace"
)
.
select_related
(
"created_by"
)
.
select_related
(
"type"
)
.
select_related
(
"territory"
)
)
.
order_by
(
"-timestamp_update"
)
.
all
()
)
class
GeoJSONPlaces
(
LoginRequiredMixin
,
...
...
@@ -20,10 +33,7 @@ class GeoJSONPlaces(
):
serializer_class
=
PlaceSerializer
pagination_class
=
LargeGeoJsonPageNumberPagination
def
get_queryset
(
self
):
qs
=
super
(
GeoJSONPlaces
,
self
).
get_queryset
()
return
qs
.
order_by
(
"-timestamp_update"
).
all
()
queryset
=
place_qs
class
GeoJSONBBoxFilteredPlaces
(
...
...
@@ -36,8 +46,4 @@ class GeoJSONBBoxFilteredPlaces(
bbox_filter_field
=
"geom"
filter_backends
=
(
InBBoxFilter
,)
bbox_filter_include_overlapping
=
True
# Optional
def
get_queryset
(
self
):
qs
=
super
(
GeoJSONBBoxFilteredPlaces
,
self
).
get_queryset
()
return
qs
.
order_by
(
"-timestamp_update"
).
all
()
queryset
=
place_qs
sights/place/views.py
View file @
64590231
...
...
@@ -146,10 +146,22 @@ class PlaceDetail(PlaceViewAuthMixin, DetailView):
def
get_context_data
(
self
,
**
kwargs
):
context
=
super
(
PlaceDetail
,
self
).
get_context_data
(
**
kwargs
)
loggeduser
=
self
.
request
.
user
logger
.
debug
(
loggeduser
)
logger
.
debug
(
f
"
loggeduser
{
loggeduser
}
f
{
dir
(
loggeduser
)
}
"
)
pk
=
self
.
kwargs
.
get
(
"pk"
)
placeobject
=
Place
.
objects
.
get
(
id_place
=
pk
)
placeobject
=
(
Place
.
objects
.
select_related
(
"territory"
)
.
prefetch_related
(
"authorized_user"
)
.
select_related
(
"created_by"
)
).
get
(
id_place
=
pk
)
sessions
=
(
Session
.
objects
.
filter
(
place
=
pk
)
.
select_related
(
"main_observer"
)
.
select_related
(
"contact"
)
.
select_related
(
"created_by"
)
.
prefetch_related
(
"other_observer"
)
.
prefetch_related
(
"sighting_set"
)
.
prefetch_related
(
"sighting_set__codesp"
)
)
# placeneighbour = Place.objects.filter(geom__within=(placeobject.geom, D(m=50)))
placedetail
=
False
# Etats des lieux à afficher en fonction du type de localité (tree, build, bridge, cave)
...
...
@@ -167,16 +179,11 @@ class PlaceDetail(PlaceViewAuthMixin, DetailView):
f
"{{% url 'sights:
{
placeobject
.
type
.
category
}
_create' pk=object.pk %}}"
)
# Données de session disponibles pour l'observateur
if
(
get_user_model
().
objects
.
filter
(
id
=
loggeduser
.
id
).
filter
(
access_all_data
=
True
))
or
(
get_user_model
().
objects
.
filter
(
id
=
loggeduser
.
id
).
filter
(
is_resp
=
True
)
and
placeobject
.
territory
in
get_user_model
().
objects
.
get
(
id
=
loggeduser
.
id
).
resp_territory
.
all
()
if
loggeduser
.
access_all_data
or
(
loggeduser
.
is_resp
and
placeobject
.
territory
in
loggeduser
.
resp_territory
.
all
()
):
# Si l'utilisateur a un accès total à toute la base
sessioncount
=
Session
.
objects
.
filter
(
place
=
pk
).
count
()
sessiontable
=
PlaceSessionTable
(
Session
.
objects
.
filter
(
place
=
pk
).
order_by
(
"-date_start"
)
)
sessions
=
sessions
elif
placeobject
in
Place
.
objects
.
filter
(
(
Q
(
is_hidden
=
True
)
&
Q
(
authorized_user__username__contains
=
loggeduser
.
username
))
|
(
Q
(
is_hidden
=
True
)
&
Q
(
created_by
=
loggeduser
))
...
...
@@ -185,23 +192,10 @@ class PlaceDetail(PlaceViewAuthMixin, DetailView):
# liste des sessions correspond aux sessions ou l'utilisateur est créateur ou observateur
# TODO Gérer la cohérence entre les restrictions de vue de la localité et celles de la table des sessions
# Filtrage, l'utilisateur doit être créateur ou l'un des observateurs de la session
sessioncount
=
Session
.
objects
.
filter
(
Q
(
place
=
pk
)
&
(
Q
(
created_by
=
loggeduser
)
|
Q
(
main_observer
=
loggeduser
)
|
Q
(
other_observer
=
loggeduser
)
)
).
count
()
sessiontable
=
PlaceSessionTable
(
Session
.
objects
.
filter
(
Q
(
place
=
pk
)
&
(
Q
(
created_by
=
loggeduser
)
|
Q
(
main_observer
=
loggeduser
)
|
Q
(
other_observer
=
loggeduser
)
)
)
sessions
=
sessions
.
filter
(
Q
(
created_by
=
loggeduser
)
|
Q
(
main_observer
=
loggeduser
)
|
Q
(
other_observer
=
loggeduser
)
)
else
:
# Si l'utilisateur est un simple observateur et que le site est non sensible, il peut en voir le détail et la
...
...
@@ -212,28 +206,16 @@ class PlaceDetail(PlaceViewAuthMixin, DetailView):
%
(
datetime
.
datetime
.
now
().
strftime
(
"%Y%m%d %I%M%S"
),
loggeduser
,
pk
)
)
if
SEE_ALL_NON_SENSITIVE_DATA
:
sessionDatas
=
Session
.
objects
.
filter
(
Q
(
place
=
pk
)
&
Q
(
is_confidential
=
False
))
sessioncount
=
sessionDatas
.
count
()
sessiontable
=
PlaceSessionTable
(
sessionDatas
)
sessions
=
sessions
.
filter
(
is_confidential
=
False
)
else
:
sessioncount
=
Session
.
objects
.
filter
(
Q
(
place
=
pk
)
&
(
Q
(
created_by
=
loggeduser
)
|
Q
(
main_observer
=
loggeduser
)
|
Q
(
other_observer
=
loggeduser
)
)
).
count
()
sessiontable
=
PlaceSessionTable
(
Session
.
objects
.
filter
(
Q
(
place
=
pk
)
&
(
Q
(
created_by
=
loggeduser
)
|
Q
(
main_observer
=
loggeduser
)
|
Q
(
other_observer
=
loggeduser
)
)
)
sessions
=
sessions
.
filter
(
Q
(
created_by
=
loggeduser
)
|
Q
(
main_observer
=
loggeduser
)
|
Q
(
other_observer
=
loggeduser
)
)
sessioncount
=
sessions
.
count
()
sessiontable
=
PlaceSessionTable
(
sessions
.
order_by
(
"-date_start"
))
context
[
"icon"
]
=
"fa fa-fw fa-map"
context
[
"title"
]
=
_
(
"Détail d'une localité"
)
context
[
...
...
Write
Preview
Supports
Markdown
0%
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!
Cancel
Please
register
or
sign in
to comment