From 3d36d986a46724b64ae35a7b7e74648f695d6954 Mon Sep 17 00:00:00 2001 From: FreneticScribbler Date: Wed, 23 Feb 2022 16:01:00 +0000 Subject: [PATCH] Add basic validation of item prerequisites Currently throws the worlds most unhelpful error message... --- training/forms.py | 7 ++++++ training/management/commands/import_old_db.py | 12 +++++----- .../migrations/0005_auto_20220223_1535.py | 22 +++++++++++++++++++ training/models.py | 9 ++++++++ training/templates/item_list.html | 17 +++++++++----- 5 files changed, 56 insertions(+), 11 deletions(-) create mode 100644 training/migrations/0005_auto_20220223_1535.py diff --git a/training/forms.py b/training/forms.py index 3897ff54..026513a3 100644 --- a/training/forms.py +++ b/training/forms.py @@ -16,6 +16,13 @@ class QualificationForm(forms.ModelForm): self.fields['trainee'].initial = Profile.objects.get(pk=pk) self.fields['date'].widget.format = '%Y-%m-%d' + def clean(self): + cleaned_data = super().clean() + item = cleaned_data.get('item') + trainee = cleaned_data.get('trainee') + if not item.user_has_requirements(trainee): + self.add_error('item', 'Missing prerequisites') + def clean_date(self): date = self.cleaned_data['date'] if date > date.today(): diff --git a/training/management/commands/import_old_db.py b/training/management/commands/import_old_db.py index 8bd59ae4..4896b555 100644 --- a/training/management/commands/import_old_db.py +++ b/training/management/commands/import_old_db.py @@ -104,19 +104,19 @@ class Command(BaseCommand): obj, created = models.TrainingItem.objects.update_or_create( pk=int(child.find('ID').text), reference_number=number, - name=name, + description=name, category=category, active=active ) except IntegrityError: - print("Training Item {}.{} {} has a duplicate reference number".format(category.reference_number, number, name)) + print(f"Training Item {category.reference_number}.{number} {name} has a duplicate reference number") if created: tally[1] += 1 else: tally[0] += 1 - print('Training Items - Updated: {}, Created: {}'.format(tally[0], tally[1])) + print(f'Training Items - Updated: {tally[0]}, Created: {tally[1]}') def import_TrainingItemQualification(self): tally = [0, 0, 0] @@ -129,9 +129,9 @@ class Command(BaseCommand): ("Competency_Assessed", models.TrainingItemQualification.PASSED_OUT), ] for (depth, depth_index) in depths: - if child.find('{}_Date'.format(depth)) is not None: - if child.find('{}_Assessor_ID'.format(depth)) is None: - print("Training Record #{} had no supervisor. Assigning System User.".format(child.find('ID').text)) + if child.find(f'{depth}_Date') is not None: + if child.find(f'{depth}_Assessor_ID') is None: + print(f"Training Record #{child.find('ID').text} had no supervisor. Assigning System User.") supervisor = Profile.objects.get(first_name="God") continue supervisor = Profile.objects.get(pk=self.id_map[child.find('{}_Assessor_ID'.format(depth)).text]) diff --git a/training/migrations/0005_auto_20220223_1535.py b/training/migrations/0005_auto_20220223_1535.py new file mode 100644 index 00000000..39f44303 --- /dev/null +++ b/training/migrations/0005_auto_20220223_1535.py @@ -0,0 +1,22 @@ +# Generated by Django 3.2.12 on 2022-02-23 15:35 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('training', '0004_rename_name_trainingitem_description'), + ] + + operations = [ + migrations.AlterModelOptions( + name='trainingcategory', + options={'ordering': ['reference_number'], 'verbose_name_plural': 'Training Categories'}, + ), + migrations.AddField( + model_name='trainingitem', + name='prerequisites', + field=models.ManyToManyField(blank=True, to='training.TrainingItem'), + ), + ] diff --git a/training/models.py b/training/models.py index 272c2e53..0e8ec5dd 100644 --- a/training/models.py +++ b/training/models.py @@ -75,6 +75,7 @@ class TrainingCategory(models.Model): class Meta: verbose_name_plural = 'Training Categories' + ordering = ['reference_number'] class TrainingItemManager(QueryablePropertiesManager): @@ -92,6 +93,7 @@ class TrainingItem(models.Model): category = models.ForeignKey('TrainingCategory', related_name='items', on_delete=models.CASCADE) description = models.CharField(max_length=50) active = models.BooleanField(default=True) + prerequisites = models.ManyToManyField('self', symmetrical=False, blank=True) objects = TrainingItemManager() @@ -124,6 +126,13 @@ class TrainingItem(models.Model): def get_absolute_url(self): return reverse('item_list') + def has_prereqs(self): + return self.prerequisites.all().exists() + + def user_has_requirements(self, user): + # Always true if there are no prerequisites, otherwise get a set of prerequsite IDs and check if they are a subset of the set of qualification IDs + return not self.has_prereqs() or set(self.prerequisites.values_list('pk', flat=True)).issubset(set(user.qualifications_obtained.values_list('item', flat=True))) + @staticmethod def user_has_qualification(item, user, depth): return user.qualifications_obtained.only('item', 'depth').filter(item=item, depth__gte=depth).exists() diff --git a/training/templates/item_list.html b/training/templates/item_list.html index 9303fe34..47a990d3 100644 --- a/training/templates/item_list.html +++ b/training/templates/item_list.html @@ -13,11 +13,18 @@
{% for item in category.items.all %} - {% if item.active %} -
  • {{ item }}
  • - {% elif request.user.is_superuser %} -
  • {{ item }}
  • - {% endif %} +
  • {{ item }} + {% if item.prerequisites.exists %} +
    +

    Prerequisites:

    +
      + {% for p in item.prerequisites.all %} +
    • {{p}}
    • + {% endfor %} +
    +
    + {% endif %} +
  • {% endfor %}