mirror of
https://github.com/nottinghamtec/PyRIGS.git
synced 2026-01-25 17:32:16 +00:00
Somewhat optimised SQL on level detail
This commit is contained in:
12
Pipfile
12
Pipfile
@@ -19,7 +19,7 @@ cssselect = "~=1.1.0"
|
|||||||
cssutils = "~=1.0.2"
|
cssutils = "~=1.0.2"
|
||||||
dj-database-url = "~=0.5.0"
|
dj-database-url = "~=0.5.0"
|
||||||
dj-static = "~=0.0.6"
|
dj-static = "~=0.0.6"
|
||||||
Django = "~=3.1.12"
|
Django = "~=3.2"
|
||||||
django-debug-toolbar = "~=3.2"
|
django-debug-toolbar = "~=3.2"
|
||||||
django-filter = "~=2.4.0"
|
django-filter = "~=2.4.0"
|
||||||
django-ical = "~=1.7.1"
|
django-ical = "~=1.7.1"
|
||||||
@@ -89,14 +89,8 @@ pytest-django = "*"
|
|||||||
pluggy = "*"
|
pluggy = "*"
|
||||||
pytest-splinter = "*"
|
pytest-splinter = "*"
|
||||||
pytest = "*"
|
pytest = "*"
|
||||||
|
pytest-xdist = {extras = [ "psutil",], version = "*"}
|
||||||
|
PyPOM = {extras = [ "splinter",], version = "*"}
|
||||||
|
|
||||||
[requires]
|
[requires]
|
||||||
python_version = "3.9"
|
python_version = "3.9"
|
||||||
|
|
||||||
[dev-packages.pytest-xdist]
|
|
||||||
extras = [ "psutil",]
|
|
||||||
version = "*"
|
|
||||||
|
|
||||||
[dev-packages.PyPOM]
|
|
||||||
extras = [ "splinter",]
|
|
||||||
version = "*"
|
|
||||||
|
|||||||
@@ -260,3 +260,5 @@ USE_GRAVATAR = True
|
|||||||
|
|
||||||
TERMS_OF_HIRE_URL = "http://www.nottinghamtec.co.uk/terms.pdf"
|
TERMS_OF_HIRE_URL = "http://www.nottinghamtec.co.uk/terms.pdf"
|
||||||
AUTHORISATION_NOTIFICATION_ADDRESS = 'productions@nottinghamtec.co.uk'
|
AUTHORISATION_NOTIFICATION_ADDRESS = 'productions@nottinghamtec.co.uk'
|
||||||
|
|
||||||
|
DEFAULT_AUTO_FIELD = 'django.db.models.AutoField'
|
||||||
|
|||||||
@@ -18,10 +18,7 @@ class Trainee(Profile, RevisionMixin):
|
|||||||
return [level for level in TrainingLevel.objects.all() if level.percentage_complete(self) > 0]
|
return [level for level in TrainingLevel.objects.all() if level.percentage_complete(self) > 0]
|
||||||
|
|
||||||
def level_qualifications(self, only_confirmed=False):
|
def level_qualifications(self, only_confirmed=False):
|
||||||
levels = self.levels.all()
|
return self.levels.all().filter(confirmed_on__isnull=only_confirmed).select_related('level')
|
||||||
if only_confirmed:
|
|
||||||
levels = levels.exclude(confirmed_on__isnull=True)
|
|
||||||
return levels.select_related('level')
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_supervisor(self):
|
def is_supervisor(self):
|
||||||
@@ -38,8 +35,7 @@ class Trainee(Profile, RevisionMixin):
|
|||||||
return self.qualifications_obtained.filter(depth=depth).select_related('item', 'trainee', 'supervisor')
|
return self.qualifications_obtained.filter(depth=depth).select_related('item', 'trainee', 'supervisor')
|
||||||
|
|
||||||
def is_user_qualified_in(self, item, required_depth):
|
def is_user_qualified_in(self, item, required_depth):
|
||||||
qual = self.qualifications_obtained.filter(item=item).first() # this is a somewhat ghetto version of get_or_none
|
return self.qualifications_obtained.values('item', 'depth').filter(item=item).filter(depth__gte=required_depth).first() is not None # this is a somewhat ghetto version of get_or_none
|
||||||
return qual is not None and qual.depth >= required_depth
|
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return reverse('trainee_detail', kwargs={'pk': self.pk})
|
return reverse('trainee_detail', kwargs={'pk': self.pk})
|
||||||
@@ -93,8 +89,8 @@ class TrainingItemQualification(models.Model):
|
|||||||
(PASSED_OUT, 'Passed Out'),
|
(PASSED_OUT, 'Passed Out'),
|
||||||
)
|
)
|
||||||
item = models.ForeignKey('TrainingItem', on_delete=models.RESTRICT)
|
item = models.ForeignKey('TrainingItem', on_delete=models.RESTRICT)
|
||||||
trainee = models.ForeignKey('Trainee', related_name='qualifications_obtained', on_delete=models.RESTRICT)
|
|
||||||
depth = models.IntegerField(choices=CHOICES)
|
depth = models.IntegerField(choices=CHOICES)
|
||||||
|
trainee = models.ForeignKey('Trainee', related_name='qualifications_obtained', on_delete=models.RESTRICT)
|
||||||
date = models.DateField()
|
date = models.DateField()
|
||||||
# TODO Remember that some training is external. Support for making an organisation the trainer?
|
# TODO Remember that some training is external. Support for making an organisation the trainer?
|
||||||
supervisor = models.ForeignKey('Trainee', related_name='qualifications_granted', on_delete=models.RESTRICT)
|
supervisor = models.ForeignKey('Trainee', related_name='qualifications_granted', on_delete=models.RESTRICT)
|
||||||
@@ -189,18 +185,8 @@ class TrainingLevel(models.Model, RevisionMixin):
|
|||||||
def passed_out_requirements(self):
|
def passed_out_requirements(self):
|
||||||
return self.get_requirements_of_depth(TrainingItemQualification.PASSED_OUT)
|
return self.get_requirements_of_depth(TrainingItemQualification.PASSED_OUT)
|
||||||
|
|
||||||
def get_related_level(self, dif):
|
def percentage_complete(self, user):
|
||||||
if (level == 0 and dif < 0) or (level == 2 and dif > 0):
|
needed_qualifications = self.requirements.all().select_related('item')
|
||||||
return None
|
|
||||||
return TrainingLevel.objects.get(department=self.department, level=self.level+dif)
|
|
||||||
|
|
||||||
def get_common_competencies(self):
|
|
||||||
if is_common_competencies:
|
|
||||||
return self
|
|
||||||
return TrainingLevel.objects.get(level=self.level, department=None)
|
|
||||||
|
|
||||||
def percentage_complete(self, user): # FIXME
|
|
||||||
needed_qualifications = self.requirements.all().select_related()
|
|
||||||
relavant_qualifications = 0.0
|
relavant_qualifications = 0.0
|
||||||
# TODO Efficiency...
|
# TODO Efficiency...
|
||||||
for req in needed_qualifications:
|
for req in needed_qualifications:
|
||||||
|
|||||||
@@ -70,7 +70,7 @@
|
|||||||
<div class="alert alert-warning mx-auto">No qualifications in any levels yet...did someone forget to fill out the paperwork?</div>
|
<div class="alert alert-warning mx-auto">No qualifications in any levels yet...did someone forget to fill out the paperwork?</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
<h3>In Progress</h3>
|
<h3 class="col-12 pt-2">In Progress</h3>
|
||||||
<div class="card-columns">
|
<div class="card-columns">
|
||||||
{% for level in started_levels %}
|
{% for level in started_levels %}
|
||||||
{% percentage_complete level object as completion %}
|
{% percentage_complete level object as completion %}
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
<th scope="row" class="align-middle" id="cell_name">{{ object.item }}</th>
|
<th scope="row" class="align-middle" id="cell_name">{{ object.item }}</th>
|
||||||
<td class="table-{% colour_from_depth object.depth %}">{{ object.get_depth_display }}</td>
|
<td class="table-{% colour_from_depth object.depth %}">{{ object.get_depth_display }}</td>
|
||||||
<td>{{ object.date }}</td>
|
<td>{{ object.date }}</td>
|
||||||
<td>{{ object.supervisor }}</td>
|
<td><a href="{{ object.supervisor.get_absolute_url}}">{{ object.supervisor }}</a></td>
|
||||||
<td>{{ object.notes }}</td>
|
<td>{{ object.notes }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% empty %}
|
{% empty %}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ from PyRIGS.views import OEmbedView, is_ajax, ModalURLMixin
|
|||||||
from training import models, forms
|
from training import models, forms
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
from django.db.models import Q, Count
|
from django.db.models import Q, Count, OuterRef, F, Subquery, Window
|
||||||
|
|
||||||
from users import views
|
from users import views
|
||||||
|
|
||||||
@@ -37,12 +37,8 @@ class TraineeDetail(views.ProfileDetail):
|
|||||||
else:
|
else:
|
||||||
context["page_title"] = "{}'s Training Record".format(self.object.first_name + " " + self.object.last_name)
|
context["page_title"] = "{}'s Training Record".format(self.object.first_name + " " + self.object.last_name)
|
||||||
context["started_levels"] = self.object.started_levels()
|
context["started_levels"] = self.object.started_levels()
|
||||||
context["completed_levels"] = self.object.level_qualifications()
|
context["completed_levels"] = self.object.level_qualifications().select_related('level')
|
||||||
context["categories"] = models.TrainingCategory.objects.all().prefetch_related('items')
|
context["categories"] = models.TrainingCategory.objects.all().prefetch_related('items')
|
||||||
choices = models.TrainingItemQualification.CHOICES
|
|
||||||
context["depths"] = choices
|
|
||||||
for i in [x for x, _ in choices]:
|
|
||||||
context[str(i)] = self.object.get_records_of_depth(i)
|
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
@@ -101,7 +97,7 @@ class TraineeList(generic.ListView):
|
|||||||
# not an integer
|
# not an integer
|
||||||
pass
|
pass
|
||||||
|
|
||||||
return self.model.objects.filter(filter).annotate(num_qualifications=Count('qualifications_obtained')).order_by('-num_qualifications').prefetch_related('levels', 'qualifications_obtained')
|
return self.model.objects.filter(filter).annotate(num_qualifications=Count('qualifications_obtained')).order_by('-num_qualifications').prefetch_related('levels', 'qualifications_obtained', 'qualifications_obtained__item')
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = super().get_context_data(**kwargs)
|
context = super().get_context_data(**kwargs)
|
||||||
|
|||||||
Reference in New Issue
Block a user