class TagCaption(index.Indexed, ClusterableModel): tags = TaggableManager('Теги', through=TagCaptionTag, blank=True) raw_content = RichTextField('Текст') @property def content(self): return richtext(self.raw_content) paneles = [FieldPanel('tags'), FieldPanel('content')] def __str__(self): return ' / '.join(self.tags.all().values_list('name', flat=True)) search_fields = [ index.SearchField('tags'), index.RelatedFields('tags', [ index.SearchField('slug'), index.FilterField('slug'), ]), ] api_fields = [ APIField('tags', serializer=serializers.TagSerializer()), APIField('content') ] class Meta: verbose_name = 'Примечание' verbose_name_plural = 'Примечания'
class GuidelinePage(Page): parent_page_types = ['guidelines.GuidelinesIndexPage'] subpage_types = [] subtitle = RichTextField('Подзаголовок', blank=True, null=True) # поле для ввода текста raw_content = RichTextField('Содержание', blank=True) tags = ClusterTaggableManager(through='guidelines.GuidelinePageTag', blank=True) publish_date = models.DateField('Дата', blank=True, null=True, default=get_default_date) @property # тут получаем текст с валидными тегами def text(self): return richtext(self.raw_content) @property def section_title(self): return self.get_parent().title @property def section_url(self): return self.get_parent().url @property def breadcrumbs(self): breadcrumbs = [] for page in self.get_ancestors()[2:]: breadcrumbs.append({'title': page.title, 'url': page.url}) return breadcrumbs @property def tags_slugs(self): return '\n'.join(self.tags.all().values_list('slug', flat=True)) @property def clean_preview(self): h = html2text.HTML2Text() h.ignore_links = True h.ignore_emphasis = True h.ignore_images = True if self.subtitle: raw_text = h.handle(self.subtitle) else: raw_text = h.handle(self.raw_content) if len(raw_text) > 310: raw_text = raw_text[:310] space_index = raw_text.rfind(' ') raw_text = raw_text[:space_index] + '...' return raw_text.replace('\n', ' ').strip() content_panels = Page.content_panels + [ MultiFieldPanel([FieldPanel("tags")], heading="Теги"), FieldPanel('subtitle'), FieldPanel('raw_content'), FieldPanel('publish_date'), MultiFieldPanel([ InlinePanel( "guideline_authors", label="Author", min_num=0, max_num=4) ], heading="Автор(ы)") ] search_fields = Page.search_fields + [ index.RelatedFields('guideline_authors', [ index.SearchField('full_name', partial_match=True), index.SearchField('alias') ]), index.SearchField('publish_date'), index.SearchField('text'), index.RelatedFields('tags', [ index.SearchField('slug'), index.FilterField('slug'), ]), index.SearchField('tags_slugs', partial_match=True), ] api_fields = [ APIField('breadcrumbs'), APIField('section_title'), APIField('section_url'), APIField('subtitle'), APIField('text'), APIField('tags', serializer=serializers.TagSerializer()), APIField('publish_date'), APIField('tags_slugs'), APIField('authors', serializer=serializers.AuthorSerializer( source='guideline_authors')), APIField('clean_preview'), ] def clean(self): super().clean() # автоматически создаем слаг if self.slug == 'default-blank-slug': if len(self.title) > 20: self.slug = slugify(self.title[:20]) else: self.slug = slugify(self.title) if '--' in self.slug: self.slug = self.slug.replace('--', '-') if self.slug.endswith('-'): self.slug = self.slug[:-1] def get_sitemap_urls(self, request): return [{ 'location': self.full_url[:-1], 'lastmod': self.last_published_at, }] class Meta: verbose_name = 'Памятка' verbose_name_plural = 'Памятки'
class ConsPageSerializer(serializers.ModelSerializer): tags = b_s.TagSerializer() class Meta: model = ConsPage fields = ('number', 'content', 'title', 'slug', 'tags')
class LawPage(Page): parent_page_types = ['legislation.LawsSectionPage'] subpage_types = [] full_title = models.TextField("Полное название", max_length=900, null=True) raw_subtitle = RichTextField(verbose_name='Подзаголовок', blank=True) content = RichTextField(verbose_name='Содержание', blank=True) note = models.CharField(verbose_name='Примечание', max_length=300, blank=True) doc = models.ForeignKey('base.CustomDocument', blank=True, null=True, on_delete=models.SET_NULL, related_name='+', verbose_name="Документ") publish_date = models.DateField( "Дата обнародования", blank=True, null=True, help_text='Дата, с которой начинается действие документа') tags = ClusterTaggableManager(through='legislation.LawPageTag', blank=True) @property def subtitle(self): return richtext(self.raw_subtitle) @property def text(self): return richtext(self.content) @property def is_obsolete(self): if 'утрат' in self.note: return True else: return False @property def breadcrumbs(self): breadcrumbs = [] for page in self.get_ancestors()[2:]: breadcrumbs.append({'title': page.title, 'url': page.url}) return breadcrumbs @property def section_title(self): return self.get_parent().title @property def section_url(self): return self.get_parent().url @property def tags_slugs(self): return '\n'.join(self.tags.all().values_list('slug', flat=True)) @property def clean_preview(self): h = html2text.HTML2Text() h.ignore_links = True h.ignore_emphasis = True h.ignore_images = True if self.subtitle: raw_text = h.handle(self.subtitle) else: raw_text = h.handle(self.raw_content) if len(raw_text) > 310: raw_text = raw_text[:310] space_index = raw_text.rfind(' ') raw_text = raw_text[:space_index] + '...' return raw_text.replace('\n', ' ').strip() def clean(self): super().clean() # автоматически создаем слаг и заголовок if len(self.full_title) >= 254: self.title = self.full_title[:254] else: self.title = self.full_title if self.slug == 'default-blank-slug': if self.doc: dot_index = self.doc.filename.rfind('.') filename = self.doc.filename[:dot_index] self.slug = slugify(filename) elif len(self.title) > 100: self.slug = slugify(self.title[:100]) else: self.slug = slugify(self.title) if '--' in self.slug: self.slug = self.slug.replace('--', '-') if self.slug.endswith('-'): self.slug = self.slug[:-1] def get_sitemap_urls(self, request): return [{ 'location': self.full_url[:-1], 'lastmod': self.last_published_at, }] content_panels = [ FieldPanel('full_title'), FieldPanel('raw_subtitle'), FieldPanel('note'), FieldPanel('publish_date'), DocumentChooserPanel('doc'), FieldPanel('tags'), MultiFieldPanel([InlinePanel("related_docs", label='Документ')], heading='Связанные документы'), FieldPanel('content'), ] search_fields = Page.search_fields + [ index.SearchField('full_title'), index.SearchField('subtitle'), index.SearchField('content'), index.SearchField('tags'), index.RelatedFields('tags', [ index.SearchField('slug'), index.FilterField('slug'), index.FilterField('name'), index.SearchField('name') ]), index.SearchField('tags_slugs', partial_match=True), index.SearchField('publish_date'), index.FilterField('publish_date'), ] api_fields = [ APIField('full_title'), APIField('subtitle'), APIField('note'), APIField('text'), APIField('doc', serializer=base_serializers.DocSerializer()), APIField('breadcrumbs'), APIField('section_title'), APIField('section_url'), APIField('publish_date', serializer=base_serializers.DateSerializer()), APIField('tags', serializer=base_serializers.TagSerializer()), APIField('related_docs', serializer=serializers.RelatedDocsSerializer()), APIField('clean_preview'), APIField('tags_slugs') ] class Meta: verbose_name = 'Законодательный акт' verbose_name_plural = 'Законодательные акты'
class BlogArticlePage(Page): """ Запись в блоге """ parent_page_types = ['blog.BlogIndexPage'] subpage_types = [] raw_subtitle = RichTextField(null=True, blank=True) content = StreamField([('full_richtext', base_blocks.RichTextBlock()), ('table', TableBlock(label='Таблица')), ('raw_html', RawHTMLBlock(label='HTML'))], null=True, blank=True, help_text='Содержание') tags = ClusterTaggableManager(through='blog.BlogPageTag', blank=True) publish_date = models.DateField(blank=True, null=True) @property def subtitle(self): return richtext(self.raw_subtitle) @property def breadcrumbs(self): breadcrumbs = [] for page in self.get_ancestors()[2:]: breadcrumbs.append({'title': page.title, 'url': page.url}) return breadcrumbs @property def section_title(self): title = self.get_parent().title if 'Дискуссионные вопросы' in title: return 'Дискуссионные вопросы' else: return title @property def section_url(self): return self.get_parent().url @property def tags_slugs(self): return '\n'.join(self.tags.all().values_list('slug', flat=True)) @property def clean_preview(self): h = html2text.HTML2Text() h.ignore_links = True h.ignore_emphasis = True h.ignore_images = True if self.subtitle: raw_text = h.handle(self.subtitle) else: raw_text = h.handle(self.content[0].value.source) if len(raw_text) > 310: raw_text = raw_text[:310] space_index = raw_text.rfind(' ') raw_text = raw_text[:space_index] + '...' return raw_text.replace('\n', ' ').strip() content_panels = Page.content_panels + [ FieldPanel('raw_subtitle', heading='Подзаголовок'), StreamFieldPanel('content', heading='Содержание'), MultiFieldPanel([ InlinePanel("blog_authors", label="Author", min_num=1, max_num=4) ], heading="Автор(ы)"), MultiFieldPanel([FieldPanel("tags")], heading="Теги"), FieldPanel('publish_date') ] search_fields = Page.search_fields + [ index.RelatedFields('blog_authors', [ index.SearchField('full_name', partial_match=True), index.SearchField('alias') ]), index.SearchField('tags_slugs', partial_match=True), index.SearchField('subtitle'), index.SearchField('content'), index.SearchField('publish_date'), index.FilterField('publish_date') ] api_fields = [ APIField('breadcrumbs'), APIField('section_title'), APIField('section_url'), APIField('subtitle'), APIField('content'), APIField('tags', serializer=serializers.TagSerializer()), APIField( 'authors', serializer=serializers.AuthorSerializer(source='blog_authors')), APIField('publish_date', serializer=serializers.DateSerializer()), APIField('tags_slugs'), APIField('clean_preview') ] def clean(self): super().clean() # автоматически создаем слаг if self.slug == 'default-blank-slug': if len(self.title) > 30: self.slug = slugify(self.title[:30]) else: self.slug = slugify(self.title) if '--' in self.slug: self.slug = self.slug.replace('--', '-') if self.slug.endswith('-'): self.slug = self.slug[:-1] def get_sitemap_urls(self, request): return [{ 'location': self.full_url[:-1], 'lastmod': self.last_published_at, }] class Meta: verbose_name = 'Запись в блоге' verbose_name_plural = 'Записи в блогах'
class ConsPage(Page): """Страница консультации""" subpage_types = [] parent_page_types = ['cons.ConsIndexPage'] number = models.PositiveIntegerField('Номер', unique=True, default=get_default_cons_number) tags = ClusterTaggableManager('Теги', through=ConsPageTag, blank=True) publish_date = models.DateField('Дата', null=True, default=get_default_date) too_old = models.BooleanField('Устарела', default=False, null=False, ) # если конса неактаульная, ставим галочку @property def preview_client(self): ''' предпросмотр имен клиентов, задающих вопрос ''' for block in self.content: if block.block_type == 'question': clients = list() for sub_block in block.value: if sub_block.block_type == 'client': clients.append(sub_block.value) clients_str = str() for client in clients: clients_str += client clients_str += ', ' clients_str = clients_str[:-2] return clients_str @property def preview_question(self): for block in self.content: if block.block_type == 'question': for sub_block in block.value: if sub_block.block_type == 'question_text': html = sub_block.value.source soup = BeautifulSoup(html, 'html.parser') links = soup.find_all('a', href=True) if links: for link in links: link.replace_with_children() html = str(soup) if len(html) > 1000: text = html[:1000] last_dot_index = text.rfind('. ') html = text[:last_dot_index] + '...</p>' return html else: return html @property def section_title(self): return self.get_parent().title @property def section_url(self): return self.get_parent().url @property def breadcrumbs(self): breadcrumbs = [] for page in self.get_ancestors()[2:]: breadcrumbs.append({'title': page.title, 'url': page.url}) return breadcrumbs @property def clean_preview(self): h = html2text.HTML2Text() h.ignore_links = True h.ignore_emphasis = True h.ignore_images = True raw_text = h.handle(self.preview_question) return raw_text.replace('\n', ' ').strip() authors = ParentalManyToManyField(Author, blank=True) content = StreamField( [ ('question', QuestionBlock()), ('answer', AnswerBlock()), ], blank=True, verbose_name='Содержание') content_panels = [ FieldPanel("number"), FieldPanel("tags"), StreamFieldPanel("content"), FieldPanel('publish_date'), FieldPanel('too_old'), MultiFieldPanel( [InlinePanel("previous_cons", label='Консультация') ], heading='Предыдущие консультации') ] @property def tags_slugs(self): return '\n'.join(self.tags.all().values_list('slug', flat=True)) search_fields = Page.search_fields + [ index.SearchField('number'), index.FilterField('number'), index.SearchField('publish_date'), index.FilterField('publish_date'), index.SearchField('preview_client'), index.SearchField('preview_question'), index.FilterField('authors'), index.SearchField('content'), index.SearchField('tags_slugs', partial_match=True), index.RelatedFields('tags', [ index.SearchField('slug'), index.FilterField('slug'), ]), ] api_fields = [ APIField('breadcrumbs'), APIField('section_title'), APIField('section_url'), APIField('number'), APIField('tags', serializer=serializers.TagSerializer()), APIField('publish_date', serializer=serializers.DateSerializer()), APIField('authors'), APIField("preview_client"), # APIField("preview_question"), APIField("content"), APIField('previous_cons'), APIField('too_old'), APIField('tags_slugs'), APIField('authors', serializer=serializers.AuthorSerializer()), APIField('clean_preview'), ] def clean(self): super().clean() # автоматически создаем заголовок и слаг, # добавляя к номеру консультации и ее теги title = 'Консультация №' + str(self.number) + ': ' for tag in self.tags.names(): title += tag title += ', ' title = title[:-2] self.title = title slug = f'c-{str(self.number)}' self.slug = slug def save(self, *args, **kwargs): super().save() for block in self.content: if block.block_type == 'answer': # TODO удалить всех авторов на всякий случай for sub_block in block.value: if sub_block.block_type == 'author': a = Author.objects.get(id=sub_block.value.id) self.authors.add(a) return super().save(*args, **kwargs) def get_sitemap_urls(self, request): return [{ 'location': self.full_url[:-1], 'lastmod': self.last_published_at, }] class Meta: verbose_name = 'Консультация' verbose_name_plural = 'Консультации'
class FAQPage(Page): parent_page_types = ['FAQIndexPage',] subpage_types = [] number = models.PositiveIntegerField(verbose_name='Номер', unique=True, default=get_default_faq_number) tags = ClusterTaggableManager(through=FAQPageTag, blank=True, verbose_name='Теги') # поле для ввода текста raw_content = RichTextField('Содержание', blank=True) content_panels = Page.content_panels + [ FieldPanel('number'), FieldPanel('tags'), FieldPanel('raw_content'), ] @property # тут получаем текст с валидными тегами def text(self): return richtext(self.raw_content) @property def tag_slugs(self): return '\n'.join(self.tags.all().values_list('slug', flat=True)) @property def section_title(self): return self.get_parent().title @property def section_url(self): return self.get_parent().url @property def breadcrumbs(self): breadcrumbs = [] for page in self.get_ancestors()[2:]: breadcrumbs.append({'title': page.title, 'url': page.url}) return breadcrumbs @property def clean_preview(self): h = html2text.HTML2Text() h.ignore_links = True h.ignore_emphasis = True h.ignore_images = True raw_text = h.handle(self.raw_content) if len(raw_text) > 310: raw_text = raw_text[:310] space_index = raw_text.rfind(' ') raw_text = raw_text[:space_index] + '...' return raw_text.replace('\n', ' ').strip() search_fields = Page.search_fields + [ index.SearchField('number'), index.SearchField('text'), index.FilterField('tags'), index.SearchField('tag_slugs'), index.FilterField('number') ] api_fields = [ APIField('section_title'), APIField('section_url'), APIField('breadcrumbs'), APIField('number'), APIField('tags', serializer=serializers.TagSerializer()), APIField('text'), APIField('number'), APIField('clean_preview'), ] def clean(self): super().clean() if self.slug == 'default-blank-slug': slug = f'f-{str(self.number)}' if len(self.title) > 30: self.slug = slug + '-' + slugify(self.title[:30]) else: self.slug = slug + '-' + slugify(self.title) def get_sitemap_urls(self, request): return [{ 'location': self.full_url[:-1], 'lastmod': self.last_published_at, }] class Meta: verbose_name = 'Частый вопрос'
class LibraryItemPage(Page): parent_page_types = ['library.LibraryIndexPage'] subpage_types = [] raw_subtitle = RichTextField(verbose_name='Подзаголовок', blank=True, null=True) content = StreamField([('full_richtext', base_blocks.RichTextBlock()), ('table', TableBlock(label='Таблица')), ('raw_html', RawHTMLBlock(label='HTML'))], null=True, blank=True, verbose_name='Содержание') doc = models.ForeignKey('base.CustomDocument', blank=True, null=True, on_delete=models.SET_NULL, related_name='+', verbose_name="Документ") publish_date = models.DateField("Дата публикации", blank=True, null=True) tags = ClusterTaggableManager(through='library.LibraryPageTag', blank=True) @property def subtitle(self): return richtext(self.raw_subtitle) @property def breadcrumbs(self): breadcrumbs = [] for page in self.get_ancestors()[2:]: breadcrumbs.append({'title': page.title, 'url': page.url}) return breadcrumbs @property def section_title(self): return self.get_parent().title @property def section_url(self): return self.get_parent().url @property def tags_slugs(self): return '\n'.join(self.tags.all().values_list('slug', flat=True)) content_panels = Page.content_panels + [ FieldPanel('publish_date'), FieldPanel('raw_subtitle'), StreamFieldPanel('content'), MultiFieldPanel([ InlinePanel("library_authors", label="Автор", min_num=0, max_num=5) ], heading="Автор(ы)"), FieldPanel('tags'), DocumentChooserPanel('doc'), ] search_fields = Page.search_fields + [ index.SearchField('subtitle'), index.SearchField('content'), index.SearchField('tags'), index.RelatedFields('tags', [ index.SearchField('slug'), index.FilterField('slug'), index.FilterField('name'), index.SearchField('name') ]), index.SearchField('tags_slugs', partial_match=True), index.SearchField('publish_date'), index.FilterField('publish_date'), ] api_fields = [ APIField('breadcrumbs'), APIField('section_title'), APIField('section_url'), APIField('publish_date', serializer=serializers.DateSerializer()), APIField('tags', serializer=serializers.TagSerializer()), APIField('subtitle'), APIField('content'), APIField( 'authors', serializer=serializers.AuthorSerializer(source='library_authors')), APIField('doc', serializer=serializers.DocSerializer()), APIField('tags_slugs'), ] def get_sitemap_urls(self, request): return [{ 'location': self.full_url[:-1], 'lastmod': self.last_published_at, }] def clean(self): super().clean() # автоматически создаем слаг if self.slug == 'default-blank-slug': if len(self.title) > 40: self.slug = slugify(self.title[:40]) else: self.slug = slugify(self.title) if '--' in self.slug: self.slug = self.slug.replace('--', '-') if self.slug.endswith('-'): self.slug = self.slug[:-1] class Meta: verbose_name = 'Материал библиотеки' verbose_name_plural = 'Материалы библиотеки'
class SamplePage(Page): parent_page_types = ['samples.SamplesIndexPage'] subpage_types = [] raw_subtitle = RichTextField('Подзаголовок', blank=True, null=True) tags = ClusterTaggableManager(through='samples.SamplePageTag', blank=True) # поле для ввода текста raw_content = RichTextField('Содержание', blank=True) doc = models.ForeignKey('base.CustomDocument', blank=True, null=True, on_delete=models.SET_NULL, related_name='+') @property def subtitle(self): return richtext(self.raw_subtitle) @property # тут получаем текст с валидными тегами def text(self): return richtext(self.raw_content) @property def section_title(self): return self.get_parent().title @property def section_url(self): return self.get_parent().url @property def breadcrumbs(self): breadcrumbs = [] for page in self.get_ancestors()[2:]: breadcrumbs.append({'title': page.title, 'url': page.url}) return breadcrumbs @property def tags_slugs(self): return '\n'.join(self.tags.all().values_list('slug', flat=True)) @property def clean_preview(self): h = html2text.HTML2Text() h.ignore_links = True h.ignore_emphasis = True h.ignore_images = True if self.subtitle: raw_text = h.handle(self.subtitle) else: raw_text = h.handle(self.raw_content) if len(raw_text) > 310: raw_text = raw_text[:310] space_index = raw_text.rfind(' ') raw_text = raw_text[:space_index] + '...' return raw_text.replace('\n', ' ').strip() def clean(self): super().clean() # автоматически создаем слаг if self.slug == 'default-blank-slug': if len(self.title) > 30: self.slug = slugify(self.title[:30]) else: self.slug = slugify(self.title) if '--' in self.slug: self.slug = self.slug.replace('--', '-') if self.slug.endswith('-'): self.slug = self.slug[:-1] content_panels = Page.content_panels + [ FieldPanel('raw_subtitle'), FieldPanel('raw_content', heading='Содержание'), DocumentChooserPanel('doc', heading='Документ'), MultiFieldPanel([FieldPanel("tags")], heading="Теги"), ] search_fields = Page.search_fields + [ index.SearchField('subtitle'), index.SearchField('text'), index.RelatedFields('tags', [ index.SearchField('slug'), index.FilterField('slug'), ]), index.SearchField('tags_slugs', partial_match=True), ] api_fields = [ APIField('title'), APIField('breadcrumbs'), APIField('section_title'), APIField('section_url'), APIField('subtitle'), APIField('text'), APIField('tags', serializer=serializers.TagSerializer()), APIField('doc', serializer=serializers.DocSerializer()), APIField('tags_slugs'), APIField('clean_preview') ] def get_sitemap_urls(self, request): return [{ 'location': self.full_url[:-1], 'lastmod': self.last_published_at, }] class Meta: verbose_name = 'Образец документа' verbose_name_plural = 'Образец документа'
class SubjectArticlePage(Page): parent_page_types = ['SubjectIndexPage', 'SubjectArticlePage'] subpage_types = ['SubjectArticlePage'] preview_image = models.ForeignKey( 'wagtailimages.Image', on_delete=models.SET_NULL, related_name='+', null=True, blank=True ) preview_desc = models.TextField(verbose_name='Описание сюжета', max_length=800, blank=True) raw_subtitle = RichTextField(null=True, blank=True) content = StreamField( [ ('full_richtext', base_blocks.RichTextBlock()), ('table', TableBlock(label='Таблица')), ('raw_html', RawHTMLBlock(label='HTML')), ('incut', CustomPageChooserBlock(label='Врезка')) ], null=True, blank=True, help_text='Содержание') tags = ClusterTaggableManager(through='subjects.SubjectArticleTag', blank=True) publish_date = models.DateField(blank=True, null=True) news = StreamField( [ ('full_richtext', base_blocks.RichTextBlock()), ], null=True, blank=True, help_text='Новости/материалы по теме' ) @property def subtitle(self): return richtext(self.raw_subtitle) @property def tags_slugs(self): return '\n'.join(self.tags.all().values_list('slug', flat=True)) @property def clean_preview(self): h = html2text.HTML2Text() h.ignore_links = True h.ignore_emphasis = True h.ignore_images = True if self.subtitle: raw_text = h.handle(self.subtitle) else: raw_text = h.handle(self.content[0].value.source) if len(raw_text) > 310: raw_text = raw_text[:310] space_index = raw_text.rfind(' ') raw_text = raw_text[:space_index] + '...' return raw_text.replace('\n', ' ').strip() @property def breadcrumbs(self): breadcrumbs = [] for page in self.get_ancestors()[2:]: breadcrumbs.append({'title': page.title, 'url': page.url}) return breadcrumbs @property def section_title(self): title = self.get_parent().title return title @property def section_url(self): return self.get_parent().url content_panels = Page.content_panels + [ FieldPanel('raw_subtitle', heading='Подзаголовок'), StreamFieldPanel('content', heading='Содержание'), StreamFieldPanel('news', heading='Новости по теме'), MultiFieldPanel( [ InlinePanel("subject_authors", label="Автор", min_num=1, max_num=4) ], heading="Автор(ы)" ), MultiFieldPanel( [ FieldPanel("tags") ], heading="Теги" ), FieldPanel('publish_date', heading='Дата публикации'), ImageChooserPanel('preview_image', heading='Картинка для предпросмотра'), FieldPanel('preview_desc') ] api_fields = [ APIField('subtitle'), APIField('content'), APIField('authors', serializer=serializers.AuthorSerializer(source='subject_authors')), APIField('tags', serializer=serializers.TagSerializer()), APIField('publish_date', serializer=serializers.DateSerializer()), APIField('news'), APIField('clean_preview'), APIField('preview_image'), APIField('preview_desc'), APIField('breadcrumbs'), APIField('section_title'), APIField('section_url') ] search_fields = Page.search_fields + [ index.RelatedFields('subject_authors',[ index.SearchField('full_name', partial_match=True), index.SearchField('alias')]), index.SearchField('tags_slugs', partial_match=True), index.SearchField('subtitle'), index.SearchField('content'), index.SearchField('publish_date'), index.FilterField('publish_date'), index.SearchField('news') ] def clean(self): super().clean() # автоматически создаем слаг if self.slug == 'default-blank-slug': if len(self.title) > 30: self.slug = slugify(self.title[:30]) else: self.slug = slugify(self.title) if '--' in self.slug: self.slug = self.slug.replace('--','-') if self.slug.endswith('-'): self.slug = self.slug[:-1] def get_sitemap_urls(self, request): return [{ 'location': self.full_url[:-1], 'lastmod': self.last_published_at, }] class Meta: verbose_name = 'Страница сюжета' verbose_name_plural = "Страницы сюжетов"
class PracticePage(Page): parent_page_types = ['practice.PracticeIndexPage'] subpage_types = [] full_title = models.TextField("Полное название", max_length=800, null=True) raw_subtitle = RichTextField(verbose_name='Подзаголовок', blank=True) content = RichTextField(verbose_name='Содержание', blank=True) doc = models.ForeignKey( 'base.CustomDocument', blank=True, null=True, on_delete=models.SET_NULL, related_name='+', verbose_name= "Документ") publish_date = models.DateField("Дата обнародования", null=True) category = ForeignKey('practice.CaseCategory', blank=True, null=True, on_delete=models.SET_NULL, verbose_name="Категория дел") level = ForeignKey('practice.CourtLevel', blank=True, null=True, on_delete=models.SET_NULL, verbose_name="Уровень суда") tags = ClusterTaggableManager(through='practice.PracticePageTag', blank=True) @property def subtitle(self): return richtext(self.raw_subtitle) @property def text(self): return richtext(self.content) @property def breadcrumbs(self): breadcrumbs = [] for page in self.get_ancestors()[2:]: breadcrumbs.append({'title': page.title, 'url': page.url}) return breadcrumbs @property def section_title(self): return self.get_parent().title @property def section_url(self): return self.get_parent().url @property def tags_slugs(self): return '\n'.join(self.tags.all().values_list('slug', flat=True)) def get_sitemap_urls(self, request): return [{ 'location': self.full_url[:-1], 'lastmod': self.last_published_at, }] def clean(self): super().clean() # автоматически создаем слаг и заголовок if len(self.full_title) >= 254 : self.title = self.full_title[:254] else: self.title = self.full_title if self.slug == 'default-blank-slug': if self.doc: dot_index = self.doc.filename.rfind('.') filename = self.doc.filename[:dot_index] self.slug = slugify(filename) elif len(self.title) > 80: self.slug = slugify(self.title[:80]) else: self.slug = slugify(self.title) if '--' in self.slug: self.slug = self.slug.replace('--','-') if self.slug.endswith('-'): self.slug = self.slug[:-1] @property def clean_preview(self): h = html2text.HTML2Text() h.ignore_links = True h.ignore_emphasis = True h.ignore_images = True if self.subtitle: raw_text = h.handle(self.subtitle) else: raw_text = h.handle(self.raw_content) if len(raw_text) > 310: raw_text = raw_text[:310] space_index = raw_text.rfind(' ') raw_text = raw_text[:space_index] + '...' return raw_text.replace('\n', ' ').strip() search_fields = Page.search_fields + [ index.SearchField('full_title'), index.SearchField('subtitle'), index.SearchField('content'), index.SearchField('tags'), index.RelatedFields('tags', [ index.SearchField('slug'), index.FilterField('slug'), index.FilterField('name'), index.SearchField('name')]), index.SearchField('tags_slugs', partial_match=True), index.SearchField('category'), index.FilterField('level'), index.FilterField('category'), index.RelatedFields('category', [ index.FilterField('name'), ]), ] api_fields = [ APIField('full_title'), APIField('subtitle'), APIField('text'), APIField('doc', serializer=base_serializers.DocSerializer()), APIField('breadcrumbs'), APIField('section_title'), APIField('section_url'), APIField('publish_date', serializer=base_serializers.DateSerializer()), APIField('category', serializer=serializers.CategorySerializer()), APIField('level', serializer=serializers.LevelSerializer()), APIField('tags', serializer=base_serializers.TagSerializer()), APIField('related_docs', serializer=serializers.RelatedDocsSerializer()), APIField('clean_preview'), ] content_panels = [ FieldPanel('full_title'), FieldPanel('raw_subtitle'), FieldPanel('publish_date'), DocumentChooserPanel('doc'), FieldPanel('category', widget=forms.RadioSelect), FieldPanel('level', widget=forms.RadioSelect), FieldPanel('tags'), MultiFieldPanel([InlinePanel("related_docs", label='Документ') ], heading='Связанные документы' ), FieldPanel('content'), ] class Meta: verbose_name = 'Страница судебной практики' verbose_name_plural = 'Страницы судебной практики'