mirror of
https://github.com/nottinghamtec/PyRIGS.git
synced 2026-01-17 05:22:16 +00:00
Add description field to TrainingItems (#523)
* Add 'description' field to TrainingItems Renamed existing field to name, removed the dummy property. * Initial version of training item export view * Fix line length issue and better spacing on exported PDF * Added export button to item list * pep8 * Implement code doctor tweaks * Attempt to fix odd deployment issue * Pad headers slightly * Fix page numbering
This commit is contained in:
@@ -143,6 +143,15 @@ class Command(BaseCommand):
|
||||
"Bin Diving",
|
||||
"Wiki Editing"]
|
||||
|
||||
descriptions = [
|
||||
"Physical training concentrates on mechanistic goals: training programs in this area develop specific motor skills, agility, strength or physical fitness, often with an intention of peaking at a particular time.",
|
||||
"In military use, training means gaining the physical ability to perform and survive in combat, and learn the many skills needed in a time of war.",
|
||||
"These include how to use a variety of weapons, outdoor survival skills, and how to survive being captured by the enemy, among many others. See military education and training.",
|
||||
"While some studies have indicated relaxation training is useful for some medical conditions, autogenic training has limited results or has been the result of few studies.",
|
||||
"Some occupations are inherently hazardous, and require a minimum level of competence before the practitioners can perform the work at an acceptable level of safety to themselves or others in the vicinity.",
|
||||
"Occupational diving, rescue, firefighting and operation of certain types of machinery and vehicles may require assessment and certification of a minimum acceptable competence before the person is allowed to practice as a licensed instructor."
|
||||
]
|
||||
|
||||
for i, name in enumerate(names):
|
||||
category = random.choice(self.categories)
|
||||
previous_item = models.TrainingItem.objects.filter(category=category).last()
|
||||
@@ -150,7 +159,7 @@ class Command(BaseCommand):
|
||||
number = previous_item.reference_number + 1
|
||||
else:
|
||||
number = 0
|
||||
item = models.TrainingItem.objects.create(category=category, reference_number=number, description=name)
|
||||
item = models.TrainingItem.objects.create(category=category, reference_number=number, name=name, description=random.choice(descriptions) + random.choice(descriptions) + random.choice(descriptions))
|
||||
self.items.append(item)
|
||||
|
||||
def setup_levels(self):
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 3.2.18 on 2023-02-19 14:02
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('training', '0005_auto_20220223_1535'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RenameField(
|
||||
model_name='trainingitem',
|
||||
old_name='description',
|
||||
new_name='name',
|
||||
),
|
||||
]
|
||||
18
training/migrations/0007_trainingitem_description.py
Normal file
18
training/migrations/0007_trainingitem_description.py
Normal file
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 3.2.18 on 2023-02-19 14:02
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('training', '0006_rename_description_trainingitem_name'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='trainingitem',
|
||||
name='description',
|
||||
field=models.TextField(blank=True),
|
||||
),
|
||||
]
|
||||
@@ -85,7 +85,7 @@ class TrainingItemManager(QueryablePropertiesManager):
|
||||
def search(self, query=None):
|
||||
qs = self.get_queryset()
|
||||
if query is not None:
|
||||
or_lookup = (Q(description__icontains=query) | Q(display_id=query))
|
||||
or_lookup = (Q(name__icontains=query) | Q(description__icontains=query) | Q(display_id=query))
|
||||
qs = qs.filter(or_lookup).distinct() # distinct() is often necessary with Q lookups
|
||||
return qs
|
||||
|
||||
@@ -94,16 +94,13 @@ class TrainingItemManager(QueryablePropertiesManager):
|
||||
class TrainingItem(models.Model):
|
||||
reference_number = models.IntegerField()
|
||||
category = models.ForeignKey('TrainingCategory', related_name='items', on_delete=models.CASCADE)
|
||||
description = models.CharField(max_length=50)
|
||||
name = models.CharField(max_length=50)
|
||||
description = models.TextField(blank=True)
|
||||
active = models.BooleanField(default=True)
|
||||
prerequisites = models.ManyToManyField('self', symmetrical=False, blank=True)
|
||||
|
||||
objects = TrainingItemManager()
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return str(self)
|
||||
|
||||
@queryable_property
|
||||
def display_id(self):
|
||||
return f"{self.category.reference_number}.{self.reference_number}"
|
||||
@@ -121,7 +118,7 @@ class TrainingItem(models.Model):
|
||||
return models.Q()
|
||||
|
||||
def __str__(self):
|
||||
name = f"{self.display_id} {self.description}"
|
||||
name = f"{self.display_id} {self.name}"
|
||||
if not self.active:
|
||||
name += " (inactive)"
|
||||
return name
|
||||
@@ -149,7 +146,7 @@ class TrainingItemQualificationManager(QueryablePropertiesManager):
|
||||
def search(self, query=None):
|
||||
qs = self.get_queryset().select_related('item', 'supervisor', 'item__category')
|
||||
if query is not None:
|
||||
or_lookup = (Q(item__description__icontains=query) | Q(supervisor__first_name__icontains=query) | Q(supervisor__last_name__icontains=query) | Q(item__category__name__icontains=query) | Q(item__display_id=query))
|
||||
or_lookup = (Q(item__name__icontains=query) | Q(supervisor__first_name__icontains=query) | Q(supervisor__last_name__icontains=query) | Q(item__category__name__icontains=query) | Q(item__display_id=query))
|
||||
|
||||
try:
|
||||
or_lookup = Q(item__category__reference_number=int(query)) | or_lookup
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
{% extends 'base_training.html' %}
|
||||
|
||||
{% load button from filters %}
|
||||
|
||||
{% block content %}
|
||||
<div class="col-12 text-right py-2 pr-0">
|
||||
{% button 'print' 'item_list_export' %}
|
||||
</div>
|
||||
<div id="accordion">
|
||||
{% for category in categories %}
|
||||
<div class="card">
|
||||
@@ -13,7 +18,8 @@
|
||||
<div class="card-body">
|
||||
<div class="list-group list-group-flush">
|
||||
{% for item in category.items.all %}
|
||||
<li class="list-group-item {% if not item.active%}text-warning{%endif%}">{{ item }}
|
||||
<li class="list-group-item {% if not item.active%}text-warning{%endif%}">{{ item }} <a href="{% url 'item_qualification' item.pk %}" class="btn btn-info float-right"><span class="fas fa-user"></span> Qualified Users</a>
|
||||
<br><small>{{ item.description }}</small>
|
||||
{% if item.prerequisites.exists %}
|
||||
<div class="ml-3 font-italic">
|
||||
<p class="text-info mb-0">Passed Out Prerequisites:</p>
|
||||
@@ -24,7 +30,6 @@
|
||||
</ul>
|
||||
</div>
|
||||
{% endif %}
|
||||
<a href="{% url 'item_qualification' item.pk %}" class="btn btn-info"><span class="fas fa-user"></span> Qualified Users</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
25
training/templates/item_list.xml
Normal file
25
training/templates/item_list.xml
Normal file
@@ -0,0 +1,25 @@
|
||||
{% extends 'base_print.xml' %}
|
||||
|
||||
{% block content %}
|
||||
<h1 style="page-head">TEC Training Item List</h1>
|
||||
<spacer length="15" />
|
||||
{% for category in categories %}
|
||||
<h2 {% if not forloop.first %}style="breakbefore"{%else%}style="emheader"{%endif%}>{{category}}</h2>
|
||||
<spacer length="10" />
|
||||
{% for item in category.items.all %}
|
||||
<h3>{{ item }}</h3>
|
||||
<spacer length="4" />
|
||||
<para>{{ item.description }}</para>
|
||||
{% if item.prerequisites.exists %}
|
||||
<h4>Prerequisites:</h4>
|
||||
<ul bulletFontSize="5">
|
||||
{% for p in item.prerequisites.all %}
|
||||
<li><para>{{p}}</para></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
<spacer length="8" />
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
<namedString id="lastPage"><pageNumber/></namedString>
|
||||
{% endblock %}
|
||||
@@ -8,6 +8,7 @@ from versioning.views import VersionHistory
|
||||
|
||||
urlpatterns = [
|
||||
path('items/', login_required(views.ItemList.as_view()), name='item_list'),
|
||||
path('items/export/', login_required(views.ItemListExport.as_view()), name='item_list_export'),
|
||||
path('item/<int:pk>/qualified_users/', login_required(views.ItemQualifications.as_view()), name='item_qualification'),
|
||||
|
||||
path('trainee/list/', login_required(views.TraineeList.as_view()), name='trainee_list'),
|
||||
|
||||
@@ -7,7 +7,7 @@ from django.db import transaction
|
||||
from django.db.models import Q, Count
|
||||
from django.db.utils import IntegrityError
|
||||
|
||||
from PyRIGS.views import is_ajax, ModalURLMixin, get_related
|
||||
from PyRIGS.views import is_ajax, ModalURLMixin, get_related, PrintListView
|
||||
from training import models, forms
|
||||
from users import views
|
||||
from reversion.views import RevisionMixin
|
||||
@@ -24,6 +24,17 @@ class ItemList(generic.ListView):
|
||||
return context
|
||||
|
||||
|
||||
class ItemListExport(PrintListView):
|
||||
model = models.TrainingItem
|
||||
template_name = 'item_list.xml'
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
context['filename'] = "TrainingItemList.pdf"
|
||||
context["categories"] = models.TrainingCategory.objects.all()
|
||||
return context
|
||||
|
||||
|
||||
class TraineeDetail(views.ProfileDetail):
|
||||
template_name = "trainee_detail.html"
|
||||
model = models.Trainee
|
||||
|
||||
Reference in New Issue
Block a user