mirror of
https://github.com/nottinghamtec/PyRIGS.git
synced 2026-01-17 21:42:14 +00:00
Basic UX for adding requirements to training levels
This commit is contained in:
@@ -3,6 +3,6 @@ from training import models
|
||||
from reversion.admin import VersionAdmin
|
||||
|
||||
#admin.site.register(models.Trainee, VersionAdmin)
|
||||
admin.site.register(models.TrainingLevel, VersionAdmin)
|
||||
admin.site.register(models.TrainingCategory, VersionAdmin)
|
||||
admin.site.register(models.TrainingItem, VersionAdmin)
|
||||
admin.site.register(models.TrainingLevel, VersionAdmin)
|
||||
|
||||
@@ -18,4 +18,13 @@ class QualificationForm(forms.ModelForm):
|
||||
super(QualificationForm, self).__init__(*args, **kwargs)
|
||||
self.fields['trainee'].initial = Profile.objects.get(pk=pk)
|
||||
|
||||
|
||||
|
||||
class RequirementForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = models.TrainingLevelRequirement
|
||||
fields = '__all__'
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
pk = kwargs.pop('pk', None)
|
||||
super(RequirementForm, self).__init__(*args, **kwargs)
|
||||
self.fields['level'].initial = models.TrainingLevel.objects.get(pk=pk)
|
||||
|
||||
@@ -28,6 +28,7 @@ class Command(BaseCommand):
|
||||
with transaction.atomic():
|
||||
self.setup_categories()
|
||||
self.setup_items()
|
||||
self.setup_levels()
|
||||
|
||||
def setup_categories(self):
|
||||
names = [(1, "Basic"), (2, "Sound"), (3, "Lighting"), (4, "Rigging"), (5, "Power"), (6, "Haulage")]
|
||||
@@ -43,3 +44,6 @@ class Command(BaseCommand):
|
||||
for i,name in enumerate(names):
|
||||
item = models.TrainingItem.objects.create(category=random.choice(self.categories), reference_number=random.randint(0, 100), name=name)
|
||||
self.items.append(item)
|
||||
|
||||
def setup_levels(self):
|
||||
pass
|
||||
|
||||
42
training/migrations/0002_auto_20210706_0053.py
Normal file
42
training/migrations/0002_auto_20210706_0053.py
Normal file
@@ -0,0 +1,42 @@
|
||||
# Generated by Django 3.1.5 on 2021-07-05 23:53
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('training', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name='trainingcategory',
|
||||
options={'verbose_name_plural': 'Training Categories'},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='traininglevel',
|
||||
name='description',
|
||||
field=models.CharField(blank=True, max_length=120),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='traininglevel',
|
||||
name='prerequisite_levels',
|
||||
field=models.ManyToManyField(blank=True, related_name='prerequisites', to='training.TrainingLevel'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='traininglevel',
|
||||
name='department',
|
||||
field=models.IntegerField(choices=[(0, 'Sound'), (1, 'Lighting'), (2, 'Power'), (3, 'Rigging'), (4, 'Haulage')], null=True),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='TrainingLevelRequirement',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('depth', models.IntegerField(verbose_name=((0, 'Training Started'), (1, 'Training Complete'), (2, 'Passed Out')))),
|
||||
('item', models.ForeignKey(on_delete=django.db.models.deletion.RESTRICT, to='training.trainingitem')),
|
||||
('level', models.ForeignKey(on_delete=django.db.models.deletion.RESTRICT, related_name='requirements', to='training.traininglevel')),
|
||||
],
|
||||
),
|
||||
]
|
||||
@@ -16,6 +16,8 @@ class TrainingCategory(models.Model):
|
||||
reference_number = models.CharField(max_length=3)
|
||||
name = models.CharField(max_length=50)
|
||||
|
||||
class Meta:
|
||||
verbose_name_plural = 'Training Categories'
|
||||
|
||||
class TrainingItem(models.Model):
|
||||
reference_number = models.CharField(max_length=3)
|
||||
@@ -49,16 +51,34 @@ class TrainingItemQualification(models.Model):
|
||||
|
||||
# Levels
|
||||
class TrainingLevel(models.Model, RevisionMixin):
|
||||
description = models.CharField(max_length=120)
|
||||
description = models.CharField(max_length=120, blank=True)
|
||||
CHOICES = (
|
||||
(0, 'Technical Assistant'),
|
||||
(1, 'Technician'),
|
||||
(2, 'Supervisor'),
|
||||
)
|
||||
department = models.CharField(max_length=50, null=True) # N.B. Technical Assistant does not have a department
|
||||
DEPARTMENTS = (
|
||||
(0, 'Sound'),
|
||||
(1, 'Lighting'),
|
||||
(2, 'Power'),
|
||||
(3, 'Rigging'),
|
||||
(4, 'Haulage'),
|
||||
)
|
||||
department = models.IntegerField(choices=DEPARTMENTS, null=True) # N.B. Technical Assistant does not have a department
|
||||
level = models.IntegerField(choices=CHOICES)
|
||||
|
||||
# FIXME Common Competencies... have levels able to depend on other ones - but supervisors need to depend on both common and technican?
|
||||
prerequisite_levels = models.ManyToManyField('self', related_name='prerequisites', symmetrical=False, blank=True)
|
||||
|
||||
def __str__(self):
|
||||
return "{} {}".format(self.get_department_display(), self.get_level_display())
|
||||
|
||||
class TrainingLevelRequirement(models.Model):
|
||||
level = models.ForeignKey('TrainingLevel', related_name='requirements', on_delete=models.RESTRICT)
|
||||
item = models.ForeignKey('TrainingItem', on_delete=models.RESTRICT)
|
||||
depth = models.IntegerField(TrainingItemQualification.CHOICES)
|
||||
|
||||
def __str__(self):
|
||||
return "{} in {}".format(TrainingItemQualification.CHOICES[self.depth][1], self.item)
|
||||
|
||||
|
||||
class TrainingLevelQualification(models.Model):
|
||||
trainee = models.ForeignKey('Trainee', related_name='levels', on_delete=models.RESTRICT)
|
||||
|
||||
39
training/templates/edit_training_level.html
Normal file
39
training/templates/edit_training_level.html
Normal file
@@ -0,0 +1,39 @@
|
||||
{% extends 'base_rigs.html' %}
|
||||
|
||||
{% load static %}
|
||||
{% load widget_tweaks %}
|
||||
|
||||
{% block css %}
|
||||
{{ block.super }}
|
||||
<link rel="stylesheet" type="text/css" href="{% static 'css/selects.css' %}"/>
|
||||
{% endblock %}
|
||||
|
||||
{% block preload_js %}
|
||||
{{ block.super }}
|
||||
<script src="{% static 'js/selects.js' %}"></script>
|
||||
{% endblock %}
|
||||
|
||||
{% block js %}
|
||||
{{ block.super }}
|
||||
<script src="{% static 'js/autocompleter.js' %}"></script>
|
||||
<script src="{% static 'js/tooltip.js' %}"></script>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% if form.errors %}
|
||||
{% include 'form_errors.html' %}
|
||||
{% endif %}
|
||||
<form id="requirement-form" action="{{ form.action|default:request.path }}" method="post">{% csrf_token %}
|
||||
{% render_field form.level|attr:'hidden' value=form.trainee.initial %}
|
||||
<div class="form-group form-row">
|
||||
<label for="item_id" class="col-sm-2 col-form-label">Item</label>
|
||||
<select name="item" id="item_id" class="form-control selectpicker custom-select col-sm-10" data-live-search="true" data-sourceurl="{% url 'api_secure' model='training_item' %}" required>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group form-row">
|
||||
<label for="depth" class="col-sm-2 col-form-label">Depth</label>
|
||||
{% render_field form.depth|add_class:'form-control custom-select selectpicker col-sm'|attr:'required' %}
|
||||
</div>
|
||||
<input type="submit" class="btn btn-primary">
|
||||
</form>
|
||||
{% endblock %}
|
||||
@@ -7,7 +7,28 @@
|
||||
<div class="row mb-3">
|
||||
<h2 class="col-12">Training Levels</h2>
|
||||
{% for level in levels %}
|
||||
|
||||
<div class="card m-3">
|
||||
<h3 class="card-header"><a href="{% url 'level_edit' level.pk %}">{{ level }}</a></h3>
|
||||
<div class="card-body">
|
||||
<div class="progress mb-2">
|
||||
<div class="progress-bar progress-bar-striped" role="progressbar" style="width: 25%" aria-valuenow="25" aria-valuemin="0" aria-valuemax="100">25% complete</div>
|
||||
</div>
|
||||
<p>{{ level.description }}</p>
|
||||
<p>Requirements:
|
||||
<button class="btn btn-link" type="button" data-toggle="collapse" data-target="#reqs" aria-expanded="false" aria-controls="reqs">
|
||||
<span class="fas fa-arrow-down"></span>
|
||||
</button>
|
||||
<div class="collapse" id="reqs">
|
||||
{% for req in level.requirements.all %}
|
||||
<li>{{req}}</li>
|
||||
{% endfor %}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<button class="btn btn-success" disabled>Incomplete</button>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<div class="row">
|
||||
|
||||
@@ -15,4 +15,5 @@ urlpatterns = [
|
||||
path('trainee/<int:pk>/edit/', views.AddQualification.as_view(),
|
||||
name='edit_record'),
|
||||
path('session/', views.SessionLog.as_view(), name='session_log'),
|
||||
path('level/<int:pk>/edit/', views.AddLevelRequirement.as_view(), name='level_edit'),
|
||||
]
|
||||
|
||||
@@ -25,6 +25,7 @@ class TraineeDetail(views.ProfileDetail):
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(TraineeDetail, self).get_context_data(**kwargs)
|
||||
context["page_title"] = "{}'s Training Record".format(self.object)
|
||||
context["levels"] = models.TrainingLevel.objects.all()
|
||||
context["categories"] = models.TrainingCategory.objects.all()
|
||||
choices = models.TrainingItemQualification.CHOICES
|
||||
context["depths"] = choices
|
||||
@@ -66,3 +67,22 @@ class AddQualification(generic.CreateView):
|
||||
kwargs = super(AddQualification, self).get_form_kwargs()
|
||||
kwargs['pk'] = self.kwargs['pk']
|
||||
return kwargs
|
||||
|
||||
|
||||
class AddLevelRequirement(generic.CreateView):
|
||||
template_name = "edit_training_level.html"
|
||||
model = models.TrainingLevelRequirement
|
||||
form_class = forms.RequirementForm
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(AddLevelRequirement, self).get_context_data(**kwargs)
|
||||
context["page_title"] = "Add Requirements to Training Level {}".format(models.TrainingLevel.objects.get(pk=self.kwargs['pk']))
|
||||
return context
|
||||
|
||||
def get_form_kwargs(self):
|
||||
kwargs = super(AddLevelRequirement, self).get_form_kwargs()
|
||||
kwargs['pk'] = self.kwargs['pk']
|
||||
return kwargs
|
||||
|
||||
def get_success_url(self):
|
||||
return reverse_lazy('trainee_detail')
|
||||
|
||||
Reference in New Issue
Block a user