# Create your models here. from django.utils.text import slugify from grapple.helpers import register_query_field from wagtail.api import APIField from wagtail.core.blocks import StreamBlock from wagtail.core.fields import StreamField from wagtail.core.models import Page, Orderable from wagtail.snippets.models import register_snippet from vbv_lernwelt.learnpath.models_competences import * from vbv_lernwelt.learnpath.models_learning_unit_content import WebBasedTrainingBlock, VideoBlock @register_query_field("learning_path") class LearningPath(Page): # PageChooserPanel('related_page', 'demo.PublisherPage'), content_panels = Page.content_panels + [ InlinePanel('topics', label="Topics"), ] subpage_types = ['learnpath.Circle'] class Meta: verbose_name = "Learning Path" def __str__(self): return f"{self.title}" class Topic(Orderable): title = models.TextField(default='') is_visible = models.BooleanField(default=True) learning_path = ParentalKey('learnpath.LearningPath', null=True, blank=True, on_delete=models.CASCADE, related_name='topics', ) panels = [FieldPanel('title'), FieldPanel('is_visible'), ] api_fields = [ APIField('title'), APIField('is_visible'), ] # 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" def __str__(self): return f"{self.title}" class Circle(Page): 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.LearningPath'] subpage_types = ['learnpath.LearningUnit'] content_panels = Page.content_panels + [ FieldPanel('description'), FieldPanel('goals'), InlinePanel('learning_sequences', label="Learning Sequences"), ] api_fields = [ APIField('title'), APIField('description'), APIField('topic'), APIField('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}" @register_snippet class LearningSequence(Orderable): # TODO: How to do a icon choice field? title = models.CharField(max_length=256, default='') circle = ParentalKey( 'learnpath.Circle', null=True, blank=True, on_delete=models.CASCADE, related_name='learning_sequences', ) panels = [FieldPanel('title'), FieldPanel('circle')] api_fields = [ APIField('title'), APIField('category'), APIField('learning_packages'), ] class Meta: verbose_name = "Learning Sequence" def __str__(self): return f"{self.title}" def full_clean(self, *args, **kwargs): super(LearningSequence, self).full_clean(*args, **kwargs) class LearningUnit(Page): """ This is a group of contents, with the übung and test it is one unit. ... more of a structural charactacter. """ # TODO: Review model architecture, is the stream field the right thing here? parent_page_types = ['learnpath.Circle'] learning_sequence = models.ForeignKey( 'learnpath.LearningSequence', null=True, blank=True, on_delete=models.SET_NULL, related_name='learning_units', ) content_blocks = [ ('web_based_training', WebBasedTrainingBlock()), ('video', VideoBlock()), ] contents = StreamField( StreamBlock(content_blocks), null=True, blank=True, min_num=1, max_num=1 ) content_panels = [ FieldPanel('title', classname="full title"), FieldPanel('learning_sequence'), StreamFieldPanel('contents'), ] api_fields = [ APIField('title'), APIField('contents'), APIField('content_blocks'), ] subpage_types = [] 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