Experiment with new model structure

This commit is contained in:
Lorenz Padberg 2022-05-02 13:42:37 +02:00
parent eb289ed729
commit 19eafd8b35
9 changed files with 201 additions and 176 deletions

View File

@ -1,7 +1,10 @@
# Generated by Django 3.2.12 on 2022-04-04 14:52
# Generated by Django 3.2.12 on 2022-04-26 12:15
from django.db import migrations, models
import django.db.models.deletion
import modelcluster.fields
import wagtail.core.blocks
import wagtail.core.fields
class Migration(migrations.Migration):
@ -17,7 +20,8 @@ class Migration(migrations.Migration):
name='Circle',
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')),
('description', models.TextField(default='')),
('description', models.TextField(blank=True, default='')),
('goals', models.TextField(blank=True, default='')),
],
options={
'verbose_name': 'Circle',
@ -34,35 +38,46 @@ class Migration(migrations.Migration):
},
bases=('wagtailcore.page',),
),
migrations.CreateModel(
name='LearningSequence',
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': 'homepage',
},
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')),
('contents', wagtail.core.fields.StreamField([('web_based_training', wagtail.core.blocks.StructBlock([('url', wagtail.core.blocks.URLBlock())])), ('video', wagtail.core.blocks.StructBlock([('url', wagtail.core.blocks.URLBlock())]))], blank=True, null=True)),
],
options={
'verbose_name': 'Learning Unig',
'verbose_name': 'Learning Unit',
},
bases=('wagtailcore.page',),
),
migrations.CreateModel(
name='Topic',
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')),
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('sort_order', models.IntegerField(blank=True, editable=False, null=True)),
('title', models.TextField(default='')),
('is_visible', models.BooleanField(default=True)),
('learning_path', modelcluster.fields.ParentalKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='topics', to='learnpath.learningpath')),
],
options={
'verbose_name': 'Topic',
},
bases=('wagtailcore.page',),
),
migrations.CreateModel(
name='LearningSequence',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('sort_order', models.IntegerField(blank=True, editable=False, null=True)),
('title', models.CharField(default='', max_length=256)),
('category', models.CharField(choices=[('INCIRCLE', 'In Circle'), ('START', 'Start'), ('END', 'End')], default='INCIRCLE', max_length=16)),
('circle', modelcluster.fields.ParentalKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='learning_sequences', to='learnpath.circle')),
],
options={
'verbose_name': 'Learning Sequence',
},
),
migrations.AddField(
model_name='circle',
name='topic',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='circles', to='learnpath.topic'),
),
]

View File

@ -1,18 +0,0 @@
# Generated by Django 3.2.12 on 2022-04-04 15:46
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('learnpath', '0001_initial'),
]
operations = [
migrations.AlterField(
model_name='circle',
name='description',
field=models.TextField(blank=True, default=''),
),
]

View File

@ -0,0 +1,23 @@
# Generated by Django 3.2.12 on 2022-04-27 08:58
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('learnpath', '0001_initial'),
]
operations = [
migrations.AddField(
model_name='circle',
name='sort_order',
field=models.IntegerField(blank=True, editable=False, null=True),
),
migrations.AddField(
model_name='learningunit',
name='sort_order',
field=models.IntegerField(blank=True, editable=False, null=True),
),
]

View File

@ -1,18 +0,0 @@
# Generated by Django 3.2.12 on 2022-04-12 12:48
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('learnpath', '0002_alter_circle_description'),
]
operations = [
migrations.AddField(
model_name='circle',
name='goals',
field=models.TextField(blank=True, default=''),
),
]

View File

@ -1,26 +0,0 @@
# Generated by Django 3.2.12 on 2022-04-14 13:03
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('learnpath', '0003_circle_goals'),
]
operations = [
migrations.AlterModelOptions(
name='learningsequence',
options={'verbose_name': 'Learning Sequence'},
),
migrations.AlterModelOptions(
name='learningunit',
options={'verbose_name': 'Learning Unit'},
),
migrations.AddField(
model_name='learningsequence',
name='category',
field=models.CharField(choices=[('INCIRCLE', 'In Circle'), ('START', 'Start'), ('END', 'End')], default='INCIRCLE', max_length=16),
),
]

View File

@ -1,20 +0,0 @@
# Generated by Django 3.2.12 on 2022-04-19 09:37
from django.db import migrations
import wagtail.core.blocks
import wagtail.core.fields
class Migration(migrations.Migration):
dependencies = [
('learnpath', '0004_auto_20220414_1503'),
]
operations = [
migrations.AddField(
model_name='learningunit',
name='contents',
field=wagtail.core.fields.StreamField([('web_based_training', wagtail.core.blocks.StructBlock([('url', wagtail.core.blocks.URLBlock())])), ('video', wagtail.core.blocks.StructBlock([('url', wagtail.core.blocks.URLBlock())]))], blank=True, null=True),
),
]

View File

@ -1,11 +1,12 @@
# Create your models here.
from django.db import models
from wagtail.admin.edit_handlers import FieldPanel, StreamFieldPanel, PageChooserPanel, InlinePanel
from modelcluster.fields import ParentalKey
from wagtail.admin.edit_handlers import FieldPanel, StreamFieldPanel, InlinePanel
from wagtail.core.blocks import StreamBlock
from wagtail.core.fields import StreamField
from wagtail.core.models import Page
from modelcluster.fields import ParentalKey
from wagtail.core.models import Page, Orderable
from django.utils.text import slugify
from vbv_lernwelt.learnpath.models_learning_unit_content import WebBasedTrainingBlock, VideoBlock
@ -14,14 +15,11 @@ from vbv_lernwelt.learnpath.models_learning_unit_content import WebBasedTraining
class LearningPath(Page):
# PageChooserPanel('related_page', 'demo.PublisherPage'),
content_panels = Page.content_panels + [
FieldPanel('title', classname="full"),
InlinePanel('topics', label="Topics"),
]
subpage_types = ['learnpath.Topic']
subpage_types = ['learnpath.Circle']
class Meta:
verbose_name = "Learning Path"
@ -30,23 +28,32 @@ class LearningPath(Page):
return f"{self.title}"
class Topic(Page):
class Topic(Orderable):
title = models.TextField(default='')
is_visible = models.BooleanField(default=True)
learning_path = ParentalKey(
'learnpath.LearningPath',
learning_path = ParentalKey('learnpath.LearningPath',
null=True,
blank=True,
on_delete=models.SET_NULL,
on_delete=models.CASCADE,
related_name='topics',
)
content_panels = Page.content_panels + [
FieldPanel('is_visible', classname="full"),
PageChooserPanel('learning_path', 'learnpath.LearningPath'),
panels = [FieldPanel('title'),
FieldPanel('is_visible'),
]
parent_page_types = ['learnpath.LearningPath']
subpage_types = ['learnpath.Circle']
# content_panels = Page.content_panels + [
# FieldPanel('is_visible', classname="full"),
# PageChooserPanel('learning_path', 'learnpath.LearningPath'),
# ]
# parent_page_types = ['learnpath.LearningPath']
# subpage_types = ['learnpath.Circle']
def full_clean(self, *args, **kwargs):
self.slug = find_available_slug(Topic, slugify(self.title, allow_unicode=True))
super(Topic, self).full_clean(*args, **kwargs)
class Meta:
verbose_name = "Topic"
@ -55,23 +62,36 @@ class Topic(Page):
return f"{self.title}"
class Circle(Page):
class Circle(Page, Orderable):
description = models.TextField(default="", blank=True)
goals = models.TextField(default="", blank=True)
topic = models.ForeignKey(
'learnpath.Topic',
null=True,
blank=True,
on_delete=models.SET_NULL,
related_name='circles'
)
parent_page_types = ['learnpath.Topic']
subpage_types = ['learnpath.LearningSequence']
parent_page_types = ['learnpath.Learningpath']
subpage_types = ['learnpath.LearningUnit']
content_panels = Page.content_panels + [
FieldPanel('description'),
FieldPanel('topic'),
FieldPanel('goals'),
#InlinePanel('circle', label="Learning Sequences"),
InlinePanel('learning_sequences', label="Learning Sequences"),
]
def full_clean(self, *args, **kwargs):
self.slug = find_available_slug(Circle, slugify(self.title, allow_unicode=True))
super(Circle, self).full_clean(*args, **kwargs)
class Meta:
verbose_name = "Circle"
def __str__(self):
return f"{self.title}"
@ -87,15 +107,20 @@ LEARNING_SEQUENCE_CATEGORIES = [
]
class LearningSequence(Page):
class LearningSequence(Orderable):
# TODO: How to do a icon choice field?
title = models.CharField(max_length=256, default='')
category = models.CharField(max_length=16, choices=LEARNING_SEQUENCE_CATEGORIES, default=IN_CIRCLE)
parent_page_types = ['learnpath.Circle']
subpage_types = ['learnpath.LearningUnit']
circle = ParentalKey(
'learnpath.Circle',
null=True,
blank=True,
on_delete=models.CASCADE,
related_name='learning_sequences',
)
panels = [FieldPanel('title'), FieldPanel('category')]
class Meta:
verbose_name = "Learning Sequence"
@ -104,9 +129,9 @@ class LearningSequence(Page):
return f"{self.title}"
class LearningUnit(Page):
class LearningUnit(Page, Orderable):
# TODO: Review model architecture, is the stream fiel the right thing here?
parent_page_types = ['learnpath.LearningSequence']
parent_page_types = ['learnpath.Circle']
content_blocks = [
('web_based_training', WebBasedTrainingBlock()),
@ -126,5 +151,45 @@ class LearningUnit(Page):
class Meta:
verbose_name = "Learning Unit"
def full_clean(self, *args, **kwargs):
self.slug = find_available_slug(LearningUnit, slugify(self.title, allow_unicode=True))
super(LearningUnit, self).full_clean(*args, **kwargs)
def __str__(self):
return f"{self.title}"
def find_available_slug(model, requested_slug, ignore_page_id=None):
"""
Finds an available slug within the specified parent.
If the requested slug is not available, this adds a number on the end, for example:
- 'requested-slug'
- 'requested-slug-1'
- 'requested-slug-2'
And so on, until an available slug is found.
The `ignore_page_id` keyword argument is useful for when you are updating a page,
you can pass the page being updated here so the page's current slug is not
treated as in use by another page.
"""
# TODO: In comparison ot wagtails own function, I look for the same model instead of the parent
pages = model.objects.filter(slug__startswith=requested_slug)
if ignore_page_id:
pages = pages.exclude(id=ignore_page_id)
existing_slugs = set(pages.values_list("slug", flat=True))
slug = requested_slug
number = 1
while slug in existing_slugs:
slug = requested_slug + "-" + str(number)
number += 1
return slug

View File

@ -14,20 +14,22 @@ def create_default_learning_path():
lp = LearningPathFactory.create(title="Versicherungsvermittler/in", parent=site.root_page)
tp = TopicFactory.create(title="Basis", is_visible=False, parent=lp)
tp = TopicFactory.create(title="Basis", is_visible=False, learning_path=lp)
tp.save()
circle_1 = CircleFactory.create(title="Basis", parent=tp, description="""In diesem Circle erklären wir dir, wie der Lehrgang
circle_1 = CircleFactory.create(title="Basis", parent=lp, topic=tp, description="""In diesem Circle erklären wir dir, wie der Lehrgang
Versicherungsvermittler / in " aufgebaut ist. Zudem vermitteln wir dir die wichtigsten Grundlagen,
damit erfolgreich mit deinem Lernpfad starten kannst.""")
ls_1 = LearningSequenceFactory.create(title='Einleitung', parent=circle_1)
lu_1 = LearningUnitFactory.create(title="Herzlich Willkommmen", parent=ls_1)
ls_1 = LearningSequenceFactory.create(title='Einleitung', circle=circle_1)
lu_1 = LearningUnitFactory.create(title="Herzlich Willkommmen", parent=circle_1)
ls_2 = LearningSequenceFactory.create(title='Grundlagen', parent=circle_1)
lu_1 = LearningUnitFactory.create(title="Herzlich Willkommmen", parent=ls_2)
ls_2 = LearningSequenceFactory.create(title='Grundlagen', circle=circle_1)
lu_1 = LearningUnitFactory.create(title="Aber jetzt, Butter bei die Fische", parent=circle_1)
tp = TopicFactory.create(title="Gewinnen von Kunden", parent=lp)
circle_2 = CircleFactory.create(title="Gewinnen", parent=tp, description="""Versicherungsvermittlerinnen und -vermittler verfügen über
tp = TopicFactory.create(title="Gewinnen von Kunden", learning_path=lp)
tp.save()
circle_2 = CircleFactory.create(title="Gewinnen", parent=lp, description="""Versicherungsvermittlerinnen und -vermittler verfügen über
ein starkes Netzwerk, das sie gezielt pflegen und ausbauen. Sie beraten und betreuen ihre bestehenden Kundinnen und Kunden professionell und gewinnen so ihr Vertrauen. Dadurch schaffen sie die Basis für das Gewinnen
von neuen Kundinnen und Kunden. Versicherungsvermittlerinnen und -vermittler sprechen ihre bestehenden Kundinnen
und Kunden auf Weiterempfehlung an. So nutzen sie ihre
@ -44,9 +46,9 @@ von Neukunden zu benützen
Das Thema Risiko und Sicherheit in einem Gespräch gezielt und auf die Situation des jeweiligen Gesprächspartners bezogen einfliessen zu lassen
Im täglichen Kontakt potenzielle Kundinnen und Kunden zu erkennen""")
tp = TopicFactory.create(title="Beraten der Kunden", learning_path=lp, parent=lp)
circle_3 = CircleFactory.create(title="Einstieg", parent=tp)
circle_4 = CircleFactory.create(title="Analyse", parent=tp,
tp = TopicFactory.create(title="Beraten der Kunden", learning_path=lp).save()
circle_3 = CircleFactory.create(title="Einstieg", parent=lp, topic=tp)
circle_4 = CircleFactory.create(title="Analyse", parent=lp, topic=tp,
description="""Nach dem Gespräch werten sie die Analyse aus und erstellen mit den
zur Verfügung stehenden Systemen formal korrekte Lösungsvorschläge bzw.
Ausschreibungen. Je nach Komplexität der Situation ziehen sie die nötigen
@ -59,10 +61,10 @@ von Neukunden zu benützen
Lösungsvorschläge zu skizzieren und
zu visualisieren""")
sequence_1 = LearningSequenceFactory.create(title="Starten", parent=circle_4)
learning_unit = LearningUnitFactory.create(title='Einleitung Circle "Anlayse"', parent=sequence_1)
sequence_1 = LearningSequenceFactory.create(title="Starten", circle=circle_4).save()
learning_unit = LearningUnitFactory.create(title='Einleitung Circle "Anlayse"', parent=circle_4)
learning_unit = LearningUnitFactory.create(title='** Einstieg Video"', parent=sequence_1)
learning_unit = LearningUnitFactory.create(title='** Einstieg Video"', parent=circle_4)
video_url = "https://www.vbv.ch/fileadmin/vbv/Videos/Statements_Externe/Janos_M/Testimonial_Janos_Mischler_PositiveEffekte.mp4"
video_title = "Ausbildung ist pflicht"
video_description = "Erfahren Sie, was für Janos Mischler die positiven Aspekte von ständiger Weiterbildung sind aus fachlicher und aus persönlicher Sicht."
@ -70,42 +72,43 @@ von Neukunden zu benützen
learning_unit.contents.append(('video', video_block))
learning_unit.save()
learning_unit = LearningUnitFactory.create(title='** Web Based Training"', parent=sequence_1)
learning_unit = LearningUnitFactory.create(title='** Web Based Training"', parent=circle_4)
wbt_url = "web_based_trainings/rise_cmi5_test_export/scormcontent/index.html"
wbt_block = WebBasedTrainingBlockFactory(type="web_based_training", url=wbt_url)
learning_unit.contents.append(('web_based_training', wbt_block))
learning_unit.save()
learning_unit = LearningUnitFactory.create(title="Selbsteinschätzung", parent=sequence_1)
learning_unit = LearningUnitFactory.create(title="Selbsteinschätzung", parent=circle_4)
sequence_2 = LearningSequenceFactory.create(title="Beobachten", parent=circle_4)
learning_unit = LearningUnitFactory.create(title="Mein Motorfahrzeug kaufen", parent=sequence_2)
learning_unit = LearningUnitFactory.create(title="Sich selbständig machen", parent=sequence_2)
sequence_2 = LearningSequenceFactory.create(title="Beobachten", circle=circle_4).save()
learning_unit = LearningUnitFactory.create(title="Mein Motorfahrzeug kaufen", parent=circle_4)
learning_unit = LearningUnitFactory.create(title="Sich selbständig machen", parent=circle_4)
sequence_3 = LearningSequenceFactory.create(title="Anwenden", parent=circle_4)
learning_unit = LearningUnitFactory.create(title="Nora kauft sich ein neues Auto", parent=sequence_3)
learning_unit = LearningUnitFactory.create(title="Manuel träumt von einem neuen Tesla", parent=sequence_3)
learning_unit = LearningUnitFactory.create(title="Deine Erkenntnisse und Learnings", parent=sequence_3)
sequence_3 = LearningSequenceFactory.create(title="Anwenden", circle=circle_4).save()
learning_unit = LearningUnitFactory.create(title="Nora kauft sich ein neues Auto", parent=circle_4)
learning_unit = LearningUnitFactory.create(title="Manuel träumt von einem neuen Tesla", parent=circle_4)
learning_unit = LearningUnitFactory.create(title="Deine Erkenntnisse und Learnings", parent=circle_4)
sequence_4 = LearningSequenceFactory.create(title="Üben", parent=circle_4)
learning_unit = LearningUnitFactory.create(title="Ermittlung des Kundenbedarfs", parent=sequence_4)
learning_unit = LearningUnitFactory.create(title="Aktives Zuhören", parent=sequence_4)
learning_unit = LearningUnitFactory.create(title="In Bildern Sprechen", parent=sequence_4)
learning_unit = LearningUnitFactory.create(title="Priorisieren des Bedarfs", parent=sequence_4)
learning_unit = LearningUnitFactory.create(title="Zusammenfassung des Bedarfs", parent=sequence_4)
sequence_4 = LearningSequenceFactory.create(title="Üben", circle=circle_4).save()
learning_unit = LearningUnitFactory.create(title="Ermittlung des Kundenbedarfs", parent=circle_4)
learning_unit = LearningUnitFactory.create(title="Aktives Zuhören", parent=circle_4)
learning_unit = LearningUnitFactory.create(title="In Bildern Sprechen", parent=circle_4)
learning_unit = LearningUnitFactory.create(title="Priorisieren des Bedarfs", parent=circle_4)
learning_unit = LearningUnitFactory.create(title="Zusammenfassung des Bedarfs", parent=circle_4)
sequence_5 = LearningSequenceFactory.create(title="Testen", parent=circle_4)
learning_unit = LearningUnitFactory.create(title="Bedarfsfragen", parent=sequence_5)
learning_unit = LearningUnitFactory.create(title="Andwendung der Fragetechniken", parent=sequence_5)
sequence_5 = LearningSequenceFactory.create(title="Testen", circle=circle_4).save()
learning_unit = LearningUnitFactory.create(title="Bedarfsfragen", parent=circle_4)
learning_unit = LearningUnitFactory.create(title="Andwendung der Fragetechniken", parent=circle_4)
sequence_5 = LearningSequenceFactory.create(title="Vernetzen", parent=circle_4)
learning_unit = LearningUnitFactory.create(title="Online Training", parent=sequence_5)
sequence_5 = LearningSequenceFactory.create(title="Vernetzen", circle=circle_4).save()
learning_unit = LearningUnitFactory.create(title="Online Training", parent=circle_4)
sequence_6 = LearningSequenceFactory.create(title="Beenden", parent=circle_4)
learning_unit = LearningUnitFactory.create(title="Selbsteinschätzung", parent=sequence_6)
sequence_6 = LearningSequenceFactory.create(title="Beenden", circle=circle_4).save()
learning_unit = LearningUnitFactory.create(title="Selbsteinschätzung", parent=circle_4)
circle_5 = CircleFactory.create(title="Lösung",
parent=tp,
parent=lp,
topic=tp,
goals="""— Die Daten des Kunden korrekt in die notwendigen Systeme einzutragen
Fachspezialisten beizuziehen, falls dies angezeigt ist
Mit den zur Verfügung stehenden Systemen korrekte Lösungsvorschläge
@ -114,15 +117,16 @@ von Neukunden zu benützen
Unklarheiten zu bereinigen """)
circle_6 = CircleFactory.create(title="Abschluss",
parent=tp,
parent=lp,
topic=tp,
goals="""— Je nach Komplexität der Lösungsvorschläge (z.B. Offerten oder Offertvergleich) einen Fachspezialisten aufzubieten
Sich kundenorientiert auf das Gespräch vorzubereiten und sich passend zu präsentieren""")
tp = TopicFactory.create(title="Betreuen und Ausbauen des Kundenstamms", learning_path=lp, parent=lp)
circle_7 = CircleFactory.create(title="Betreuen", parent=tp)
tp = TopicFactory.create(title="Betreuen und Ausbauen des Kundenstamms", learning_path=lp).save()
circle_7 = CircleFactory.create(title="Betreuen", parent=lp, topic=tp)
tp = TopicFactory.create(title="Prüfung", is_visible=False, learning_path=lp, parent=lp)
circle_7 = CircleFactory.create(title="Prüfungsvorbereitung", parent=tp)
tp = TopicFactory.create(title="Prüfung", is_visible=False, learning_path=lp).save()
circle_7 = CircleFactory.create(title="Prüfungsvorbereitung", parent=lp, topic=tp)
def delete_default_learning_path():

View File

@ -1,5 +1,5 @@
import wagtail_factories
import factory
from vbv_lernwelt.learnpath.models import LearningPath, Topic, Circle, LearningSequence, LearningUnit
from vbv_lernwelt.learnpath.models_learning_unit_content import VideoBlock, WebBasedTrainingBlock
@ -11,7 +11,7 @@ class LearningPathFactory(wagtail_factories.PageFactory):
model = LearningPath
class TopicFactory(wagtail_factories.PageFactory):
class TopicFactory(factory.Factory):
title = "Gewinnen von Kunden"
is_visible = True
@ -26,7 +26,7 @@ class CircleFactory(wagtail_factories.PageFactory):
model = Circle
class LearningSequenceFactory(wagtail_factories.PageFactory):
class LearningSequenceFactory(factory.Factory):
title = "Grundlagen"
class Meta: