from django.contrib.contenttypes.models import ContentType from django.db import models from django.utils.translation import ugettext_lazy as _ from oscar.core.loading import get_class from wagtail.admin.edit_handlers import ( FieldPanel, PublishingPanel, RichTextFieldPanel) from wagtail.core.fields import RichTextField from wagtail.core.models import Page class AbstractCategory(Page): is_creatable = False description = RichTextField(_('Description'), blank=True) name = models.CharField(_('Name'), max_length=255, db_index=True) image = models.ImageField(_('Image'), upload_to='categories', blank=True, null=True, max_length=255) content_panels = [ FieldPanel('title'), FieldPanel('name'), RichTextFieldPanel('description'), ] settings_panels = [ PublishingPanel(), ] class Meta: abstract = True def save(self, *args, **kwargs): if not self.name: self.name = self.title return super(AbstractCategory, self).save(*args, **kwargs) def serve(self, request, *args, **kwargs): cls = get_class('catalogue.views', 'CatalogueView') response = cls.as_view()(request, category=self, **kwargs) return response def get_ancestors_and_self(self): """ Gets ancestors and includes itself. Use treebeard's get_ancestors if you don't want to include the category itself. It's a separate function as it's commonly used in templates. """ return list(self.get_ancestors()) + [self] def get_category_ancestors(self): return ( list( self.get_ancestors() .filter(content_type=self.content_type) .specific() .order_by('depth') ) + [self]) def get_descendants_and_self(self): """ Gets descendants and includes itself. Use treebeard's get_descendants if you don't want to include the category itself. It's a separate function as it's commonly used in templates. """ return list(self.get_descendants()) + [self] def has_children(self): return self.get_num_children() > 0 def get_num_children(self): return self.get_children().count() def category_ancestors(self): content_type = ContentType.objects.get_for_model(self) return self.get_ancestors().filter(content_type=content_type) @classmethod def get_root_nodes(cls): content_type = ContentType.objects.get_for_model(cls) depth = ( cls.objects .filter(content_type=content_type) .aggregate(depth=models.Min('depth')))['depth'] if depth is not None: return cls.objects.filter(content_type=content_type, depth=depth) return cls.objects.filter(content_type=content_type)