Add course_category to LearningUnit

This commit is contained in:
Daniel Egger 2022-09-27 16:32:01 +02:00
parent 9c77526646
commit 46998668d8
16 changed files with 127 additions and 74 deletions

View File

@ -17,5 +17,5 @@ def create_default_competence_profile():
parent=competence_profile_page,
title='B1.3 Fahrzeug',
text='Innerhalb des Handlungsfelds «Fahrzeug» bin ich fähig, die Ziele und Pläne des Kunden zu ergründen (SOLL).',
learning_unit=LearningUnit.objects.get(slug='versicherungsvermittlerin-lp-circle-analyse-lu-auto-verkaufen'),
learning_unit=LearningUnit.objects.get(slug='versicherungsvermittlerin-lp-circle-analyse-lu-fahrzeug'),
)

View File

@ -1,4 +1,4 @@
# Generated by Django 3.2.13 on 2022-09-27 13:54
# Generated by Django 3.2.13 on 2022-09-27 14:26
from django.db import migrations, models
import django.db.models.deletion
@ -10,7 +10,6 @@ class Migration(migrations.Migration):
dependencies = [
('wagtailcore', '0069_log_entry_jsonfield'),
('learnpath', '0002_alter_learningcontent_contents'),
]
operations = [
@ -29,7 +28,6 @@ class Migration(migrations.Migration):
fields=[
('page_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='wagtailcore.page')),
('text', models.TextField(default='')),
('learning_unit', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='learnpath.learningunit')),
],
options={
'abstract': False,

View File

@ -0,0 +1,22 @@
# Generated by Django 3.2.13 on 2022-09-27 14:26
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
initial = True
dependencies = [
('learnpath', '0001_initial'),
('competence', '0001_initial'),
]
operations = [
migrations.AddField(
model_name='performancecriteria',
name='learning_unit',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='learnpath.learningunit'),
),
]

View File

@ -16,18 +16,18 @@ def create_versicherungsvermittlerin_with_categories(apps=None, schema_editor=No
course, _ = Course.objects.get_or_create(
id=COURSE_VERSICHERUNGSVERMITTLERIN,
name='Versicherungsvermittler/in',
title='Versicherungsvermittler/in',
category_name='Handlungsfeld'
)
CourseCategory.objects.get_or_create(course=course, name='Allgemein', general=True)
CourseCategory.objects.get_or_create(course=course, title='Allgemein', general=True)
for cat in [
'Fahrzeug', 'Reisen', 'Einkommensicherung', 'Gesundheit', 'Haushalt', 'Sparen',
'Fahrzeug', 'Reisen', 'Einkommenssicherung', 'Gesundheit', 'Haushalt', 'Sparen',
'Pensionierung', 'KMU', 'Wohneigentum', 'Rechtsstreitigkeiten', 'Erben / Vererben',
'Selbständigkeit',
]:
CourseCategory.objects.get_or_create(course=course, name=cat)
CourseCategory.objects.get_or_create(course=course, title=cat)
# create default course page
site = Site.objects.filter(is_default_site=True).first()

View File

@ -8,7 +8,7 @@ class CourseFactory(DjangoModelFactory):
class Meta:
model = Course
name = 'Versicherungsvermittler/in'
title = 'Versicherungsvermittler/in'
category_name = 'Handlungsfeld'

View File

@ -1,4 +1,4 @@
# Generated by Django 3.2.13 on 2022-09-19 14:57
# Generated by Django 3.2.13 on 2022-09-27 14:26
from django.db import migrations, models
import django.db.models.deletion
@ -17,7 +17,7 @@ class Migration(migrations.Migration):
name='Course',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=255, verbose_name='Titel')),
('title', models.CharField(max_length=255, verbose_name='Titel')),
('category_name', models.CharField(default='Kategorie', max_length=255, verbose_name='Kategorie-Name')),
],
options={
@ -39,7 +39,7 @@ class Migration(migrations.Migration):
name='CourseCategory',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(blank=True, max_length=255, verbose_name='Titel')),
('title', models.CharField(blank=True, max_length=255, verbose_name='Titel')),
('general', models.BooleanField(default=False, verbose_name='Allgemein')),
('course', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='course.course')),
],

View File

@ -7,24 +7,24 @@ from vbv_lernwelt.core.model_utils import find_available_slug
class Course(models.Model):
name = models.CharField(_('Titel'), max_length=255)
title = models.CharField(_('Titel'), max_length=255)
category_name = models.CharField(_('Kategorie-Name'), max_length=255, default='Kategorie')
class Meta:
verbose_name = _("Lerngang")
def __str__(self):
return f"{self.name}"
return f"{self.title}"
class CourseCategory(models.Model):
# Die Handlungsfelder im "Versicherungsvermittler/in"
name = models.CharField(_('Titel'), max_length=255, blank=True)
title = models.CharField(_('Titel'), max_length=255, blank=True)
course = models.ForeignKey('course.Course', on_delete=models.CASCADE)
general = models.BooleanField(_('Allgemein'), default=False)
def __str__(self):
return f"{self.course} / {self.name}"
return f"{self.course} / {self.title}"
class CoursePage(Page):

View File

@ -6,10 +6,10 @@ from vbv_lernwelt.course.models import CourseCategory, Course
class CourseSerializer(serializers.ModelSerializer):
class Meta:
model = Course
fields = ['id', 'name', 'category_name']
fields = ['id', 'title', 'category_name']
class CourseCategorySerializer(serializers.ModelSerializer):
class Meta:
model = CourseCategory
fields = ['id', 'name', 'general',]
fields = ['id', 'title', 'general',]

View File

@ -6,7 +6,7 @@ from wagtail_localize.models import LocaleSynchronization
from vbv_lernwelt.core.admin import User
from vbv_lernwelt.course.consts import COURSE_VERSICHERUNGSVERMITTLERIN
from vbv_lernwelt.course.models import CoursePage
from vbv_lernwelt.course.models import CoursePage, CourseCategory
from vbv_lernwelt.learnpath.models import LearningPath, Topic, Circle, LearningSequence, LearningContent, LearningUnit, \
LearningUnitQuestion
from vbv_lernwelt.learnpath.tests.learning_path_factories import LearningPathFactory, TopicFactory, CircleFactory, \
@ -63,6 +63,7 @@ def create_circle_children(circle, title):
lu = LearningUnitFactory(
title='Absicherung der Familie',
parent=circle,
course_category=CourseCategory.objects.get(course_id=COURSE_VERSICHERUNGSVERMITTLERIN, title='Einkommenssicherung')
)
LearningUnitQuestionFactory(
title="Ich bin in der Lage, mit geeigneten Fragestellungen die Deckung von Versicherungen zu erfassen.",
@ -122,7 +123,10 @@ def create_circle_children(circle, title):
)
LearningSequenceFactory(title='Anwenden', parent=circle, icon='it-icon-ls-apply')
lu = LearningUnitFactory(title='Prämien einsparen', parent=circle)
lu = LearningUnitFactory(
title='Prämien einsparen',
parent=circle,
)
LearningUnitQuestionFactory(
title="Passende Frage zu Anwenden",
parent=lu
@ -140,7 +144,11 @@ def create_circle_children(circle, title):
contents=[('exercise', ExerciseBlockFactory())]
)
lu = LearningUnitFactory(title='Sich selbständig machen', parent=circle)
lu = LearningUnitFactory(
title='Sich selbständig machen',
parent=circle,
course_category=CourseCategory.objects.get(course_id=COURSE_VERSICHERUNGSVERMITTLERIN, title='Selbständigkeit')
)
LearningUnitQuestionFactory(
title="Passende Frage zu 'Sich selbständig machen'",
parent=lu
@ -158,7 +166,11 @@ def create_circle_children(circle, title):
contents=[('exercise', ExerciseBlockFactory())]
)
lu = LearningUnitFactory(title='Auto verkaufen', parent=circle)
lu = LearningUnitFactory(
title='Auto verkaufen',
parent=circle,
course_category=CourseCategory.objects.get(course_id=COURSE_VERSICHERUNGSVERMITTLERIN, title='Fahrzeug')
)
LearningUnitQuestionFactory(
title='Passende Frage zu "Auto verkaufen"',
parent=lu
@ -188,7 +200,11 @@ def create_circle_children(circle, title):
contents=[('exercise', ExerciseBlockFactory(url='/static/media/web_based_trainings/training-04-a-01-rafael-fasel-wechselt-sein-auto-einstieg/scormcontent/index.html'))]
)
lu = LearningUnitFactory(title='Pensionierung', parent=circle)
lu = LearningUnitFactory(
title='Pensionierung',
parent=circle,
course_category=CourseCategory.objects.get(course_id=COURSE_VERSICHERUNGSVERMITTLERIN, title='Pensionierung')
)
LearningUnitQuestionFactory(
title='Passende Frage zu "Pensionierung"',
parent=lu
@ -218,7 +234,11 @@ def create_circle_children(circle, title):
contents=[('exercise', ExerciseBlockFactory())]
)
lu = LearningUnitFactory(title='Reisen', parent=circle)
lu = LearningUnitFactory(
title='Reisen',
parent=circle,
course_category=CourseCategory.objects.get(course_id=COURSE_VERSICHERUNGSVERMITTLERIN, title='Reisen')
)
LearningUnitQuestionFactory(
title='Passende Frage zu "Reisen"',
parent=lu
@ -237,7 +257,11 @@ def create_circle_children(circle, title):
url='/static/media/web_based_trainings/story-06-a-01-emma-und-ayla-campen-durch-amerika-einstieg/scormcontent/index.html'))]
)
lu = LearningUnitFactory(title='Haushalt', parent=circle)
lu = LearningUnitFactory(
title='Haushalt',
parent=circle,
course_category=CourseCategory.objects.get(course_id=COURSE_VERSICHERUNGSVERMITTLERIN, title='Haushalt')
)
LearningUnitQuestionFactory(
title='Passende Frage zu "Haushalt"',
parent=lu
@ -262,7 +286,11 @@ def create_circle_children(circle, title):
)
LearningSequenceFactory(title='Üben', parent=circle, icon='it-icon-ls-practice')
lu = LearningUnitFactory(title='Kind zieht von zu Hause aus', parent=circle)
lu = LearningUnitFactory(
title='Kind zieht von zu Hause aus',
parent=circle,
course_category=CourseCategory.objects.get(course_id=COURSE_VERSICHERUNGSVERMITTLERIN, title='Einkommenssicherung')
)
LearningUnitQuestionFactory(
title='Passende Frage zu "Kind zieht von zu Hause aus"',
parent=lu
@ -287,7 +315,11 @@ def create_circle_children(circle, title):
)
LearningSequenceFactory(title='Testen', parent=circle, icon='it-icon-ls-test')
lu = LearningUnitFactory(title='Kind zieht von zu Hause aus "Testen"', parent=circle)
lu = LearningUnitFactory(
title='Kind zieht von zu Hause aus "Testen"',
parent=circle,
course_category=CourseCategory.objects.get(course_id=COURSE_VERSICHERUNGSVERMITTLERIN, title='Einkommenssicherung')
)
LearningUnitQuestionFactory(
title='Passende Frage zu "Kind zieht von zu Hause aus"',
parent=lu

View File

@ -1,4 +1,4 @@
# Generated by Django 3.2.13 on 2022-09-19 15:05
# Generated by Django 3.2.13 on 2022-09-27 14:26
from django.db import migrations, models
import django.db.models.deletion
@ -13,6 +13,7 @@ class Migration(migrations.Migration):
dependencies = [
('wagtailcore', '0069_log_entry_jsonfield'),
('course', '0001_initial'),
]
operations = [
@ -35,7 +36,7 @@ class Migration(migrations.Migration):
fields=[
('page_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='wagtailcore.page')),
('minutes', models.PositiveIntegerField(default=15)),
('contents', wagtail.fields.StreamField([('video', wagtail.blocks.StructBlock([('description', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('web_based_training', wagtail.blocks.StructBlock([('description', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('podcast', wagtail.blocks.StructBlock([('description', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('competence', wagtail.blocks.StructBlock([('description', wagtail.blocks.TextBlock())])), ('exercise', wagtail.blocks.StructBlock([('description', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('document', wagtail.blocks.StructBlock([('description', wagtail.blocks.TextBlock())])), ('knowledge', wagtail.blocks.StructBlock([('description', wagtail.blocks.TextBlock())]))], use_json_field=None)),
('contents', wagtail.fields.StreamField([('video', wagtail.blocks.StructBlock([('description', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('resource', wagtail.blocks.StructBlock([('description', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('exercise', wagtail.blocks.StructBlock([('description', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('online_training', wagtail.blocks.StructBlock([('description', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('media_library', wagtail.blocks.StructBlock([('description', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('document', wagtail.blocks.StructBlock([('description', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('test', wagtail.blocks.StructBlock([('description', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('book', wagtail.blocks.StructBlock([('description', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('assignment', wagtail.blocks.StructBlock([('description', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())]))], use_json_field=None)),
],
options={
'verbose_name': 'Learning Content',
@ -63,16 +64,6 @@ class Migration(migrations.Migration):
},
bases=('wagtailcore.page',),
),
migrations.CreateModel(
name='LearningUnit',
fields=[
('page_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='wagtailcore.page')),
],
options={
'verbose_name': 'Learning Unit',
},
bases=('wagtailcore.page',),
),
migrations.CreateModel(
name='LearningUnitQuestion',
fields=[
@ -94,4 +85,15 @@ class Migration(migrations.Migration):
},
bases=('wagtailcore.page',),
),
migrations.CreateModel(
name='LearningUnit',
fields=[
('page_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='wagtailcore.page')),
('course_category', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='course.coursecategory')),
],
options={
'verbose_name': 'Learning Unit',
},
bases=('wagtailcore.page',),
),
]

View File

@ -1,20 +0,0 @@
# Generated by Django 3.2.13 on 2022-09-27 13:54
from django.db import migrations
import wagtail.blocks
import wagtail.fields
class Migration(migrations.Migration):
dependencies = [
('learnpath', '0001_initial'),
]
operations = [
migrations.AlterField(
model_name='learningcontent',
name='contents',
field=wagtail.fields.StreamField([('video', wagtail.blocks.StructBlock([('description', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('resource', wagtail.blocks.StructBlock([('description', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('exercise', wagtail.blocks.StructBlock([('description', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('online_training', wagtail.blocks.StructBlock([('description', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('media_library', wagtail.blocks.StructBlock([('description', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('document', wagtail.blocks.StructBlock([('description', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('test', wagtail.blocks.StructBlock([('description', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('book', wagtail.blocks.StructBlock([('description', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('assignment', wagtail.blocks.StructBlock([('description', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())]))], use_json_field=None),
),
]

View File

@ -8,6 +8,7 @@ from wagtail.images.blocks import ImageChooserBlock
from wagtail.models import Page
from vbv_lernwelt.core.model_utils import find_available_slug
from vbv_lernwelt.course.models import CoursePage
from vbv_lernwelt.learnpath.models_learning_unit_content import VideoBlock, \
ExerciseBlock, DocumentBlock, AssignmentBlock, BookBlock, MediaLibraryBlock, \
OnlineTrainingBlock, ResourceBlock, TestBlock
@ -165,6 +166,11 @@ class LearningSequence(Page):
class LearningUnit(Page):
parent_page_types = ['learnpath.Circle']
subpage_types = []
course_category = models.ForeignKey('course.CourseCategory', on_delete=models.SET_NULL, null=True, blank=True)
content_panels = Page.content_panels + [
FieldPanel('course_category'),
]
class Meta:
verbose_name = "Learning Unit"
@ -173,7 +179,18 @@ class LearningUnit(Page):
return f"{self.title}"
def full_clean(self, *args, **kwargs):
self.slug = find_slug_with_parent_prefix(self, 'lu')
course = None
course_parent_page = self.get_ancestors().exact_type(CoursePage).last()
if course_parent_page:
course = course_parent_page.specific.course
if self.course_category is None and course:
self.course_category = course.coursecategory_set.filter(general=True).first()
if self.course_category.general:
self.slug = find_slug_with_parent_prefix(self, 'lu')
else:
self.slug = find_slug_with_parent_prefix(self, 'lu', self.course_category.title)
super(LearningUnit, self).full_clean(*args, **kwargs)
@classmethod
@ -265,11 +282,14 @@ class LearningContent(Page):
return f"{self.title}"
def find_slug_with_parent_prefix(page, type_prefix):
def find_slug_with_parent_prefix(page, type_prefix, slug_postfix=None):
parent_slug = page.get_ancestors().exact_type(LearningPath, Circle).last().slug
if parent_slug:
slug_prefix = f"{parent_slug}-{type_prefix}"
else:
slug_prefix = type_prefix
return find_available_slug(slugify(f'{slug_prefix}-{page.title}', allow_unicode=True))
if slug_postfix is None:
slug_postfix = page.title
return find_available_slug(slugify(f'{slug_prefix}-{slug_postfix}', allow_unicode=True))

View File

@ -14,9 +14,9 @@ def create_default_collections():
root, created = Collection.objects.get_or_create(name='Root', depth=0)
for course in Course.objects.all():
course_collection = root.add_child(name=course.name)
course_collection = root.add_child(name=course.title)
for cat in course.coursecategory_set.all():
cat_collection = course_collection.add_child(name=cat.name)
cat_collection = course_collection.add_child(name=cat.title)
def create_default_documents():

View File

@ -43,7 +43,7 @@ welche Aspekte du bei einer Offerte beachten musst und wie du dem Kunden die Lö
])
media_category = MediaCategoryPageFactory(
overview_icon=overview_icon,
title=cat.name,
title=cat.title,
course_category=cat,
parent=media_lib_page,
introduction_text=introduction_text,

View File

@ -1,16 +1,15 @@
# Generated by Django 3.2.13 on 2022-09-23 15:27
# Generated by Django 3.2.13 on 2022-09-27 14:26
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import taggit.managers
import vbv_lernwelt.media_library.content_blocks
import wagtail.blocks
import wagtail.documents.blocks
import wagtail.fields
import wagtail.models.collections
import wagtail.search.index
from django.conf import settings
from django.db import migrations, models
import vbv_lernwelt.media_library.content_blocks
class Migration(migrations.Migration):
@ -18,10 +17,10 @@ class Migration(migrations.Migration):
initial = True
dependencies = [
('wagtailcore', '0069_log_entry_jsonfield'),
('taggit', '0004_alter_taggeditem_content_type_alter_taggeditem_tag'),
('course', '0001_initial'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('wagtailcore', '0069_log_entry_jsonfield'),
('taggit', '0004_alter_taggeditem_content_type_alter_taggeditem_tag'),
]
operations = [
@ -54,7 +53,7 @@ class Migration(migrations.Migration):
('items', wagtail.fields.StreamField([('item', wagtail.blocks.TextBlock())], use_json_field=True)),
('overview_icon', models.CharField(default='icon-hf-fahrzeug', max_length=255)),
('body', wagtail.fields.StreamField([('content_collection', wagtail.blocks.StructBlock([('title', wagtail.blocks.TextBlock()), ('contents', wagtail.blocks.StreamBlock([('Links', wagtail.blocks.StructBlock([('title', wagtail.blocks.TextBlock(blank=False, null=False)), ('description', wagtail.blocks.TextBlock(default='')), ('link_display_text', wagtail.blocks.CharBlock(default='Link öffnen', max_length=255)), ('url', wagtail.blocks.URLBlock())])), ('Documents', wagtail.documents.blocks.DocumentChooserBlock()), ('Ankers', vbv_lernwelt.media_library.content_blocks.AnchorBlock()), ('CrossReference', wagtail.blocks.StructBlock([('description', wagtail.blocks.TextBlock(default='')), ('link_display_text', wagtail.blocks.CharBlock(default='Link öffnen', max_length=255)), ('category', wagtail.blocks.PageChooserBlock(page_type=['media_library.MediaCategoryPage']))]))]))]))], null=True, use_json_field=True)),
('course_category', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='course.coursecategory')),
('course_category', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='course.coursecategory')),
],
options={
'abstract': False,

View File

@ -38,7 +38,7 @@ class MediaCategoryPage(Page):
"""
Handlungsfeld. zB. Fahrzeug
"""
course_category = models.ForeignKey('course.CourseCategory', on_delete=models.CASCADE)
course_category = models.ForeignKey('course.CourseCategory', on_delete=models.SET_NULL, null=True, blank=True)
parent_page_types = ['media_library.MediaLibraryPage']
introduction_text = models.TextField(default='')
description_title = models.TextField(default='Das erwartet dich in diesem Handlungsfeld')