From f34c119c6807986a4fbf791d596427a7b238c1fa Mon Sep 17 00:00:00 2001
From: Mary Kate Fain
Date: Mon, 5 Nov 2018 12:03:50 -0500
Subject: [PATCH] Add software tag to exercises sction, fixes #68
---
.../migrations/0008_auto_20181105_1140.py | 33 +++++++++++++++++++
project_tier/exercises/models.py | 23 ++++++++++++-
.../exercises/exercise_index_page.html | 23 +++++++++++++
project_tier/static/js/filters.js | 2 +-
4 files changed, 79 insertions(+), 2 deletions(-)
create mode 100644 project_tier/exercises/migrations/0008_auto_20181105_1140.py
diff --git a/project_tier/exercises/migrations/0008_auto_20181105_1140.py b/project_tier/exercises/migrations/0008_auto_20181105_1140.py
new file mode 100644
index 00000000..5341de82
--- /dev/null
+++ b/project_tier/exercises/migrations/0008_auto_20181105_1140.py
@@ -0,0 +1,33 @@
+# Generated by Django 2.0.4 on 2018-11-05 16:40
+
+from django.db import migrations, models
+import django.db.models.deletion
+import modelcluster.contrib.taggit
+import modelcluster.fields
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('taggit', '0002_auto_20150616_2121'),
+ ('exercises', '0007_exerciseindexpage_notes'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='SoftwareTag',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('content_object', modelcluster.fields.ParentalKey(on_delete=django.db.models.deletion.CASCADE, related_name='software_tags_relationship', to='exercises.ExercisePage')),
+ ('tag', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='exercises_softwaretag_items', to='taggit.Tag')),
+ ],
+ options={
+ 'abstract': False,
+ },
+ ),
+ migrations.AddField(
+ model_name='exercisepage',
+ name='software_tags',
+ field=modelcluster.contrib.taggit.ClusterTaggableManager(blank=True, help_text='A comma-separated list of tags.', related_name='+', through='exercises.SoftwareTag', to='taggit.Tag', verbose_name='software tags'),
+ ),
+ ]
diff --git a/project_tier/exercises/models.py b/project_tier/exercises/models.py
index 64eb361c..4e5a02b2 100644
--- a/project_tier/exercises/models.py
+++ b/project_tier/exercises/models.py
@@ -32,6 +32,7 @@
changing the actual tagging API within Wagtail or django-taggit.
"""
+
class DisciplineTag(TaggedItemBase):
content_object = ParentalKey(
'exercises.ExercisePage',
@@ -59,6 +60,15 @@ class ProtocolTag(TaggedItemBase):
)
+class SoftwareTag(TaggedItemBase):
+ content_object = ParentalKey(
+ 'exercises.ExercisePage',
+ # django-modelcluster requires this to be set
+ related_name='software_tags_relationship',
+ on_delete=models.CASCADE
+ )
+
+
class ExercisePage(Page):
cover_sheet = models.ForeignKey(
'wagtaildocs.Document',
@@ -120,6 +130,13 @@ class ExercisePage(Page):
blank=True,
verbose_name="protocol tags"
)
+ software_tags = ClusterTaggableManager(
+ through=SoftwareTag,
+ # disabling reverse accessors solves a naming clash
+ related_name="+",
+ blank=True,
+ verbose_name="software tags"
+ )
parent_page_types = ['exercises.ExerciseIndexPage']
@@ -130,6 +147,7 @@ class ExercisePage(Page):
FieldPanel('discipline_tags'),
FieldPanel('course_level_tags'),
FieldPanel('protocol_tags'),
+ FieldPanel('software_tags'),
],
heading="tags",
),
@@ -170,13 +188,16 @@ def get_context(self, request):
exercises_courseleveltag_items__isnull=False).distinct()
context['protocol_tags'] = Tag.objects.filter(
exercises_protocoltag_items__isnull=False).distinct()
+ context['software_tags'] = Tag.objects.filter(
+ exercises_softwaretag_items__isnull=False).distinct()
# Filters exercises by the tag name in the URL
tag_groups = [
# (The name in the URL, the name of the Python model attribute)
('disciplines', 'discipline'),
('course-levels', 'course_level'),
- ('protocols', 'protocol')
+ ('protocols', 'protocol'),
+ ('softwares', 'software'),
]
# Loop through the given tag groups from above
for tag_group in tag_groups:
diff --git a/project_tier/exercises/templates/exercises/exercise_index_page.html b/project_tier/exercises/templates/exercises/exercise_index_page.html
index 6d9697c4..64f57061 100644
--- a/project_tier/exercises/templates/exercises/exercise_index_page.html
+++ b/project_tier/exercises/templates/exercises/exercise_index_page.html
@@ -54,6 +54,20 @@ Protocol
{% endif %}
+ {% if software_tags %}
+
+
Software
+ {% for tag in software_tags %}
+
+
+
+ {{ tag }}
+
+
+ {% endfor %}
+
+ {% endif %}
+
{% if results.filtered %}
Clear filters
@@ -88,6 +102,12 @@ Protocol
{% endfor %}
{% endif %}
+ {% if software_tags_checked %}
+ {% for tag in software_tags_checked %}
+ {{ tag }}
+ {% endfor %}
+ {% endif %}
+
Clear all filters
@@ -118,6 +138,9 @@ {{ exercise.title }}
{% for tag in exercise.specific.protocol_tags.all %}
{{ tag }}
{% endfor %}
+ {% for tag in exercise.specific.software_tags.all %}
+ {{ tag }}
+ {% endfor %}
{{ exercise.specific.listing_excerpt|truncatechars_html:100 }}
diff --git a/project_tier/static/js/filters.js b/project_tier/static/js/filters.js
index 372ee500..a52dceab 100644
--- a/project_tier/static/js/filters.js
+++ b/project_tier/static/js/filters.js
@@ -16,7 +16,7 @@ function serializeFilters() {
var tags = $('.exercise-filter input[type="checkbox"]:checked');
// Loop each tag type and build the query string
var queryString = '?';
- var tagTypes = ['disciplines', 'course-levels', 'protocols'];
+ var tagTypes = ['disciplines', 'course-levels', 'protocols', 'softwares'];
for(var i=0; i