class BlogPost(BaseRichTextPage): date = models.DateField('Post Date', default=date.today) tags = ClusterTaggableManager(through=BlogPostTag, blank=True) featured = models.BooleanField(default=False, help_text="Feature this post") subpage_types = [] search_name = 'Blog post' search_fields = BaseRichTextPage.search_fields + ( index.FilterField('date'), index.FilterField('featured'), ) @property def blog_index(self): # Find blog index in ancestors for ancestor in reversed(self.get_ancestors()): if isinstance(ancestor.specific, BlogIndexPage): return ancestor # No ancestors are blog indexes, # just return first blog index in database return BlogIndexPage.objects.first()
class StaticPage(Page): # TODO: Keep it simple for now. content = RichTextField(blank=True) language = models.CharField(max_length=7, choices=settings.LANGUAGES) def __str__(self): return self.title content_panels = Page.content_panels + [ FieldPanel('content'), FieldPanel('language'), ] search_fields = Page.search_fields + [ index.SearchField('title', partial_match=True, boost=SearchBoost.TITLE), index.SearchField('language'), index.FilterField('get_search_type'), index.FilterField('language') ] def get_search_type(self): return self.__class__.__name__.lower() def get_absolute_url(self): return reverse("static_page", kwargs={"slug": self.slug})
class PressReleasePage(ContentPage): date = models.DateField(default=datetime.date.today) formatted_title = models.CharField(max_length=255, null=True, blank=True, default='', help_text="Use if you need italics in the title. e.g. <em>Italicized words</em>") category = models.CharField(max_length=255, choices=constants.press_release_page_categories.items()) read_next = models.ForeignKey('PressReleasePage', blank=True, null=True, default=get_previous_press_release_page, on_delete=models.SET_NULL) homepage_pin = models.BooleanField(default=False) homepage_pin_expiration = models.DateField(blank=True, null=True) homepage_pin_start = models.DateField(blank=True, null=True) homepage_hide = models.BooleanField(default=False) template = 'home/updates/press_release_page.html' content_panels = ContentPage.content_panels + [ FieldPanel('formatted_title'), FieldPanel('date'), InlinePanel('authors', label="Authors"), FieldPanel('category'), PageChooserPanel('read_next'), ] promote_panels = Page.promote_panels + [ MultiFieldPanel([ FieldPanel('homepage_pin'), FieldPanel('homepage_pin_start'), FieldPanel('homepage_pin_expiration'), FieldPanel('homepage_hide') ], heading="Home page feed" ) ] search_fields = ContentPage.search_fields + [ index.FilterField('category'), index.FilterField('date') ] @property def content_section(self): return '' @property def get_update_type(self): return constants.update_types['press-release'] @property def get_author_office(self): return 'Press Office' """ Because we removed the boilerplate from all 2016 releases this flag is used to show it in the templates as a print-only element """ @property def no_boilerplate(self): return self.date.year >= 2016
class Resource(Page): date = models.DateField(blank=True, null=True) content = StreamField([ ("authors", blocks.RichTextBlock(blank=True)), ("copyright", blocks.RichTextBlock(blank=True)), ("focus", blocks.RichTextBlock(blank=True)), ("factoids", blocks.RichTextBlock(blank=True)), ]) embed_url = models.URLField() embed_thumbnail = models.TextField(blank=True, null=True) categories = M2MField("category.Category", related_name="resources_by_category") language = models.CharField(max_length=7, choices=settings.LANGUAGES) search_fields = Page.search_fields + [ index.SearchField('title', partial_match=True, boost=SearchBoost.TITLE), index.SearchField('language'), index.SearchField( 'content', partial_match=True, boost=SearchBoost.CONTENT), index.FilterField('date'), index.FilterField('categories'), index.FilterField('language'), index.FilterField('get_search_type'), ] def get_search_type(self): return self.__class__.__name__.lower() def get_absolute_url(self): return reverse("resource-detail", kwargs={"slug": self.slug}) def get_template(self, request, *args, **kwargs): self.template = "resources/resource_detail.html" return super(Resource, self).get_template(request, *args, **kwargs) def get_context(self, request, *args, **kwargs): return {'resource': self, 'request': request} content_panels = Page.content_panels + [ FieldPanel('language'), FieldPanel('embed_url'), FieldPanel('embed_thumbnail'), StreamFieldPanel('content'), FieldPanel('categories'), FieldPanel('date'), ] @property def featured_image(self): return None def __str__(self): return self.title
class GoogleFormPage(Page): title_sv = models.CharField(max_length=255) translated_title = TranslatedField('title', 'title_sv') # TODO: Limit to one form! form_en = StreamField([('google_form', GoogleFormBlock())]) form_sv = StreamField([('google_form', GoogleFormBlock())]) form = TranslatedField('form_en', 'form_sv') deadline = models.DateField(verbose_name=_('Form deadline')) results_en = StreamField( WAGTAIL_STATIC_BLOCKTYPES, blank=True, ) results_sv = StreamField( WAGTAIL_STATIC_BLOCKTYPES, blank=True, ) results = TranslatedField('results_en', 'results_sv') @property def is_past_due(self) -> bool: return date.today() > self.deadline # Editor panels configuration content_panels = Page.content_panels + [ FieldPanel('title_sv', classname="full title"), FieldPanel('deadline'), StreamFieldPanel('form_en'), StreamFieldPanel('form_sv'), ] edit_handler = TabbedInterface([ ObjectList(content_panels, heading=_('Common')), ObjectList([StreamFieldPanel('results_en')], heading=_('English')), ObjectList([StreamFieldPanel('results_sv')], heading=_('Swedish')), ObjectList(Page.promote_panels + Page.settings_panels, heading=_('Settings')), ]) # Search index configuration search_fields = Page.search_fields + [ index.SearchField('title_sv'), index.FilterField('results_en'), index.FilterField('results_sv'), index.FilterField('deadline'), ] # Parent page / subpage type rules parent_page_types = ['google.GoogleFormIndex'] subpage_types = []
class NewsPage(Page): title_sv = models.CharField(max_length=255) translated_title = TranslatedField('title', 'title_sv') body_en = RichTextField() body_sv = RichTextField() body = TranslatedField('body_en', 'body_sv') created = models.DateTimeField( verbose_name=_('Created at'), auto_now_add=True, ) modified = models.DateTimeField( verbose_name=_('Modified at'), auto_now=True, ) feed_image = models.ForeignKey('wagtailimages.Image', null=True, blank=True, on_delete=models.SET_NULL, related_name='+') # Search index configuration search_fields = Page.search_fields + [ index.SearchField('title_sv'), index.SearchField('body_en'), index.SearchField('body_sv'), index.FilterField('created'), index.FilterField('modified'), ] # Editor panels configuration content_panels = Page.content_panels + [ FieldPanel('body_en', classname="full"), ] content_panels_sv = [ FieldPanel('title_sv', classname="full title"), FieldPanel('body_sv', classname="full"), ] promote_panels = [ImageChooserPanel('feed_image')] + Page.promote_panels edit_handler = TabbedInterface([ ObjectList(content_panels, heading=_('English')), ObjectList(content_panels_sv, heading=_('Swedish')), ObjectList(promote_panels, heading=_('Promote')), ObjectList(Page.settings_panels, heading=_('Settings')), ]) # Parent page / sub-page type rules parent_page_types = ['news.NewsIndexPage'] subpage_types = []
class SearchTest(index.Indexed, models.Model): title = models.CharField(max_length=255) content = models.TextField() live = models.BooleanField(default=False) published_date = models.DateField(null=True) tags = TaggableManager() search_fields = [ index.SearchField('title', partial_match=True), index.RelatedFields('tags', [ index.SearchField('name', partial_match=True), index.FilterField('slug'), ]), index.RelatedFields('subobjects', [ index.SearchField('name', partial_match=True), ]), index.SearchField('content', boost=2), index.SearchField('callable_indexed_field'), index.FilterField('title'), index.FilterField('live'), index.FilterField('published_date'), ] def callable_indexed_field(self): return "Callable" @classmethod def get_indexed_objects(cls): indexed_objects = super(SearchTest, cls).get_indexed_objects() # Exclude SearchTests that have a SearchTestChild to stop update_index creating duplicates if cls is SearchTest: indexed_objects = indexed_objects.exclude( id__in=SearchTestChild.objects.all().values_list( 'searchtest_ptr_id', flat=True)) # Exclude SearchTests that have the title "Don't index me!" indexed_objects = indexed_objects.exclude(title="Don't index me!") return indexed_objects def get_indexed_instance(self): # Check if there is a SearchTestChild that descends from this child = SearchTestChild.objects.filter( searchtest_ptr_id=self.id).first() # Return the child if there is one, otherwise return self return child or self def __str__(self): return self.title
class Book(index.Indexed, models.Model): title = models.CharField(max_length=255) authors = models.ManyToManyField(Author, related_name='books') publication_date = models.DateField() number_of_pages = models.IntegerField() tags = TaggableManager() search_fields = [ index.SearchField('title', partial_match=True, boost=2.0), index.FilterField('title'), index.RelatedFields('authors', Author.search_fields), index.FilterField('publication_date'), index.FilterField('number_of_pages'), index.RelatedFields('tags', [ index.SearchField('name'), index.FilterField('slug'), ]), ] @classmethod def get_indexed_objects(cls): indexed_objects = super(Book, cls).get_indexed_objects() # Don't index books using Book class that they have a more specific type if cls is Book: indexed_objects = indexed_objects.exclude( id__in=Novel.objects.values_list('book_ptr_id', flat=True)) indexed_objects = indexed_objects.exclude( id__in=ProgrammingGuide.objects.values_list('book_ptr_id', flat=True)) # Exclude Books that have the title "Don't index me!" indexed_objects = indexed_objects.exclude(title="Don't index me!") return indexed_objects def get_indexed_instance(self): # Check if this object is a Novel or ProgrammingGuide and return the specific object novel = Novel.objects.filter(book_ptr_id=self.id).first() programming_guide = ProgrammingGuide.objects.filter( book_ptr_id=self.id).first() # Return the novel/programming guide object if there is one, otherwise return self return novel or programming_guide or self def __str__(self): return self.title
class Lesson(Page): parent_page_types = ['lessons.LessonIndex'] date = models.DateField("Post date") body = StreamField([ ('heading', blocks.CharBlock(classname="full title", template='blocks/heading.html')), ('paragraph', blocks.RichTextBlock()), ('code', CodeBlock()), ('image', ImageChooserBlock()), ('video', EmbedBlock()), ]) search_fields = Page.search_fields + [ index.SearchField('body'), index.FilterField('date'), ] content_panels = Page.content_panels + [ FieldPanel('date'), StreamFieldPanel('body'), InlinePanel('techs', label="Mentioned technologies"), InlinePanel('books', label="Mentioned books"), InlinePanel('related_article_links', label="Related links"), ]
class Content(Page): body = StreamField([ ('heading', blocks.CharBlock(classname="full title")), ('rich_text', blocks.RichTextBlock()), ('raw', blocks.RawHTMLBlock()), ('include_content', blocks.CharBlock()), ('content_list', blocks.CharBlock()), ], null=True, blank=True) date = models.DateField("Content updated date", default=timezone.now) promote_panels = Page.promote_panels + [ FieldPanel('date'), ] content_panels = Page.content_panels + [ StreamFieldPanel('body'), ] search_fields = Page.search_fields + ( index.SearchField('body'), index.FilterField('url_path'), ) def serve(self, request): if "draft" in request.GET: return HttpResponseRedirect("/admin/pages/{}/view_draft/".format( self.pk)) return super(Content, self).serve(request) class Meta: ordering = ("date", )
class Entry(index.Indexed, models.Model): title = models.CharField('Title', max_length=255, unique=True) slug = AutoSlugField(populate_from='title') description = models.TextField('Description', ) acronym = models.BooleanField( 'Is an acronym', default=False, ) class Meta: verbose_name = 'Entry' verbose_name_plural = 'Entries' ordering = ['title'] def __str__(self): return self.title def get_absolute_url(self): return reverse('glossary:detail', args=[self.slug]) panels = [ FieldPanel('title'), # FieldPanel('slug'), FieldPanel('description'), FieldPanel('acronym'), ] search_fields = [ index.SearchField('title'), index.SearchField('description'), index.FilterField('acronym'), ]
class StandardPage(Page): body = RichTextUploadingField(blank=True) sidebar_image = models.ForeignKey('wagtailimages.Image', null=True, blank=True, on_delete=models.SET_NULL, related_name='+') sidebar_caption = models.CharField(max_length=250, blank=True) search_fields = Page.search_fields + ( # Inherit search_fields from Page index.SearchField('body'), index.FilterField('sidebar_caption'), ) content_panels = Page.content_panels + [ FieldPanel('body', classname="full"), ImageChooserPanel('sidebar_image'), FieldPanel('sidebar_caption'), ] def get_template(self, request, *args, **kwargs): parent = self.get_parent() print parent if parent is None: return "pagecontent/home_page.html" elif parent.content_type.model == 'standardpage': return "pagecontent/standard_subpage.html" else: return super(StandardPage, self).get_template(request, *args, **kwargs)
class AbstractEmbedVideo(CollectionMember, index.Indexed, models.Model): title = models.CharField(max_length=255, verbose_name=_('Title')) url = EmbedVideoField() thumbnail = models.ForeignKey(image_model_name, verbose_name=_('Thumbnail'), null=True, blank=True, on_delete=models.SET_NULL, related_name='+') created_at = models.DateTimeField(auto_now_add=True, verbose_name=_('Created')) uploaded_by_user = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, blank=True, editable=False, verbose_name=_('Uploader')) tags = TaggableManager(help_text=None, blank=True, verbose_name=_('Tags')) def get_usage(self): return get_object_usage(self) @property def usage_url(self): return reverse('wagtail_embed_videos:video_usage', args=(self.id, )) search_fields = CollectionMember.search_fields + [ index.SearchField('title', partial_match=True, boost=10), index.RelatedFields('tags', [ index.SearchField('name', partial_match=True, boost=10), ]), index.FilterField('uploaded_by_user'), ] def __str__(self): return self.title def __init__(self, *args, **kwargs): super(AbstractEmbedVideo, self).__init__(*args, **kwargs) if args: if args[3] is None: create_thumbnail(self) def save(self, *args, **kwargs): super(AbstractEmbedVideo, self).save(*args, **kwargs) if not self.thumbnail: create_thumbnail(self) @property def default_alt_text(self): return self.title def is_editable_by_user(self, user): from .permissions import permission_policy return permission_policy.user_has_permission_for_instance( user, 'change', self) class Meta: abstract = True
class Episode(Page): podcast = models.CharField(max_length=10, default="") main_image = models.ForeignKey('wagtailimages.Image', null=True, blank=True, on_delete=models.SET_NULL, related_name='+') epID = models.CharField(max_length=10, default=0) description = RichTextField(blank=True) summary = RichTextField(blank=True) published_date = models.CharField(max_length=50, default="") image_URL = models.CharField(max_length=300, default="") quote = models.CharField(max_length=300, default="", blank=True) #others = (Page.objects.all()[3].get_children()[1]) content_panels = Page.content_panels + [ FieldPanel('podcast'), FieldPanel('epID'), FieldPanel('summary'), FieldPanel('description'), FieldPanel('quote'), FieldPanel('image_URL'), ImageChooserPanel('main_image'), FieldPanel('published_date'), InlinePanel('related_links', label="Related links") ] search_fields = Page.search_fields + [ # Inherit search_fields from Page index.FilterField('podcast'), ]
class DigestPage(ContentPage): date = models.DateField(default=datetime.date.today) read_next = models.ForeignKey('DigestPage', blank=True, null=True, default=get_previous_digest_page, on_delete=models.SET_NULL) content_panels = ContentPage.content_panels + [ FieldPanel('date'), InlinePanel('authors', label="Authors"), PageChooserPanel('read_next'), ] template = 'home/updates/digest_page.html' search_fields = ContentPage.search_fields + [ index.FilterField('date') ] @property def content_section(self): return '' @property def get_update_type(self): return constants.update_types['weekly-digest'] @property def get_author_office(self): return 'Press Office'
class GenericPage(Page): # Database fields category = StreamField([('cat_title_class', blocks.CharBlock(classname="full")), ('cat_title', blocks.CharBlock(classname="full"))]) body = StreamField(InfowebStreamBlock()) date = models.DateField("Post date") feed_image = models.ForeignKey('wagtailimages.Image', null=True, blank=True, on_delete=models.SET_NULL, related_name='+') # Search index configuraiton search_fields = Page.search_fields + ( index.SearchField('body'), index.FilterField('date'), ) # Editor panels configuration content_panels = Page.content_panels + [ StreamFieldPanel('category'), StreamFieldPanel('body'), FieldPanel('date'), ] promote_panels = [ MultiFieldPanel(Page.promote_panels, "Common page configuration"), ImageChooserPanel('feed_image'), ]
class AbstractEmbedVideo(models.Model, TagSearchable): title = models.CharField(max_length=255, verbose_name=_('Title')) url = EmbedVideoField() thumbnail = models.ForeignKey('wagtailimages.Image', verbose_name="Thumbnail", null=True, blank=True, on_delete=models.SET_NULL, related_name='+') created_at = models.DateTimeField(auto_now_add=True) uploaded_by_user = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, blank=True, editable=False) tags = TaggableManager(help_text=None, blank=True, verbose_name=_('Tags')) def get_usage(self): return get_object_usage(self) @property def usage_url(self): return reverse('wagtail_embed_videos_video_usage', args=(self.id, )) search_fields = TagSearchable.search_fields + ( index.FilterField('uploaded_by_user'), ) def __str__(self): return self.title def __init__(self, *args, **kwargs): super(AbstractEmbedVideo, self).__init__(*args, **kwargs) if args: if args[3] is None: create_thumbnail(self) def save(self, *args, **kwargs): super(AbstractEmbedVideo, self).save(*args, **kwargs) if not self.thumbnail: create_thumbnail(self) @property def default_alt_text(self): return self.title def is_editable_by_user(self, user): if user.has_perm('wagtail_embed_videos.change_embedvideo'): # user has global permission to change videos return True elif user.has_perm('wagtail_embed_videos.add_embedvideo' ) and self.uploaded_by_user == user: # user has video add permission, which also implicitly provides permission to edit their own videos return True else: return False class Meta: abstract = True
class SearchTest(models.Model, index.Indexed): title = models.CharField(max_length=255) content = models.TextField() live = models.BooleanField(default=False) published_date = models.DateField(null=True) search_fields = [ index.SearchField('title', partial_match=True), index.SearchField('content'), index.SearchField('callable_indexed_field'), index.FilterField('title'), index.FilterField('live'), index.FilterField('published_date'), ] def callable_indexed_field(self): return "Callable"
def test_basic(self): cls = self.make_dummy_type([ index.SearchField('test', boost=100, partial_match=False), index.FilterField('filter_test'), ]) self.assertEqual(len(cls.get_search_fields()), 2) self.assertEqual(len(cls.get_searchable_search_fields()), 1) self.assertEqual(len(cls.get_filterable_search_fields()), 1)
def test_different_field_types_dont_override(self): # A search and filter field with the same name should be able to coexist cls = self.make_dummy_type([ index.SearchField('test', boost=100, partial_match=False), index.FilterField('test'), ]) self.assertEqual(len(cls.get_search_fields()), 2) self.assertEqual(len(cls.get_searchable_search_fields()), 1) self.assertEqual(len(cls.get_filterable_search_fields()), 1)
class GuidelinesPage(Page): strap = models.TextField(blank=True) template = 'core/guidelines.html' content = StreamField([ ("heading_title", blocks.CharBlock()), ("heading_content", blocks.RichTextBlock()), ("sub_section_with_heading", SubSectionBlock()), ("sub_section_without_heading", blocks.RichTextBlock()), ], blank=True) language = models.CharField(max_length=7, choices=settings.LANGUAGES, default="English") content_panels = Page.content_panels + [ FieldPanel('strap'), MultiFieldPanel([StreamFieldPanel('content')], heading="Content", classname="collapsible "), FieldPanel('language'), ] search_fields = Page.search_fields + [ index.FilterField('content', partial_match=True), index.SearchField('content'), index.FilterField('language'), index.SearchField('language') ] def get_context(self, request, *args, **kwargs): guideline_dict = construct_guidelines(self.content) return { 'page': self, 'request': request, 'page_content': guideline_dict, "tab": 'about-pari' } def __str__(self): return _("GuidelinesPage") def get_absolute_url(self): return reverse("static_page", kwargs={"slug": self.slug})
class Document(models.Model, TagSearchable): title = models.CharField(max_length=255, verbose_name=_('Title')) file = models.FileField(upload_to='documents', verbose_name=_('File')) created_at = models.DateTimeField(verbose_name=_('Created at'), auto_now_add=True) uploaded_by_user = models.ForeignKey(settings.AUTH_USER_MODEL, verbose_name=_('Uploaded by user'), null=True, blank=True, editable=False) tags = TaggableManager(help_text=None, blank=True, verbose_name=_('Tags')) search_fields = TagSearchable.search_fields + ( index.FilterField('uploaded_by_user'), ) def __str__(self): return self.title @property def filename(self): return os.path.basename(self.file.name) @property def file_extension(self): parts = self.filename.split('.') if len(parts) > 1: return parts[-1] else: return '' @property def url(self): return reverse('wagtaildocs_serve', args=[self.id, self.filename]) def get_usage(self): return get_object_usage(self) @property def usage_url(self): return reverse('wagtaildocs_document_usage', args=(self.id, )) def is_editable_by_user(self, user): if user.has_perm('wagtaildocs.change_document'): # user has global permission to change documents return True elif user.has_perm( 'wagtaildocs.add_document') and self.uploaded_by_user == user: # user has document add permission, which also implicitly provides permission to edit their own documents return True else: return False class Meta: verbose_name = _('Document')
class AbstractDocument(CollectionMember, index.Indexed, models.Model): title = models.CharField(max_length=255, verbose_name=_('title')) file = models.FileField(upload_to='documents', verbose_name=_('file')) created_at = models.DateTimeField(verbose_name=_('created at'), auto_now_add=True) uploaded_by_user = models.ForeignKey( settings.AUTH_USER_MODEL, verbose_name=_('uploaded by user'), null=True, blank=True, editable=False, on_delete=models.SET_NULL ) tags = TaggableManager(help_text=None, blank=True, verbose_name=_('tags')) objects = DocumentQuerySet.as_manager() search_fields = CollectionMember.search_fields + [ index.SearchField('title', partial_match=True, boost=10), index.RelatedFields('tags', [ index.SearchField('name', partial_match=True, boost=10), ]), index.FilterField('uploaded_by_user'), ] def __str__(self): return self.title @property def filename(self): return os.path.basename(self.file.name) @property def file_extension(self): return os.path.splitext(self.filename)[1][1:] @property def url(self): return reverse('wagtaildocs_serve', args=[self.id, self.filename]) def get_usage(self): return get_object_usage(self) @property def usage_url(self): return reverse('wagtaildocs:document_usage', args=(self.id,)) def is_editable_by_user(self, user): from wagtail.wagtaildocs.permissions import permission_policy return permission_policy.user_has_permission_for_instance(user, 'change', self) class Meta: abstract = True verbose_name = _('document')
class JournalDocument(AbstractDocument, ReferencedObjectMixin): ''' Override the base Document model so we can index the Document contents for search and add reference to JournalAboutPage ''' file = models.FileField( upload_to='documents', verbose_name=_('PDF document'), validators=[ FileTypeValidator( allowed_types=settings.ALLOWED_DOCUMENT_TYPES, allowed_extensions=settings.ALLOWED_DOCUMENT_FILE_EXTENSIONS) ]) search_fields = AbstractDocument.search_fields + [ index.SearchField('data', partial_match=False), index.FilterField('id'), ] admin_form_fields = Document.admin_form_fields def data(self): ''' Return the contents of the document as base64 encoded data used as input to elasticsearch ingest-attachment plugin ''' # converting to base64 is (Size * 8)/6 times bigger than binary file # determine the max number of bytes we can read to not exceed the max upload size read_max = (settings.MAX_ELASTICSEARCH_UPLOAD_SIZE * 6) / 8 self.file.open() contents = base64.b64encode(self.file.read( int(read_max))).decode('ascii') self.file.close() return contents def get_viewer_url(self, base_url): ''' Return full url to document viewer for this document ''' if self.is_pdf(): return urljoin( base_url, 'static/pdf_js/web/viewer.html?file={document_path}'.format( document_path=self.file.url) # pylint: disable=no-member ) else: return urljoin(base_url, self.file.url) # pylint: disable=no-member def is_pdf(self): return mimetypes.MimeTypes().guess_type( self.filename)[0] == 'application/pdf' def get_object_type(self): return "document"
class Content(Page): body = StreamField([ ('heading', blocks.CharBlock(classname='full title')), ('rich_text', blocks.RichTextBlock()), ('raw', blocks.RawHTMLBlock()), ('include_content', blocks.CharBlock()), ('content_list', blocks.CharBlock()), ], null=True, blank=True) date = models.DateField('Content updated date', default=timezone.now) template_filename = models.CharField(max_length=64, choices=( ('content.html', 'content.html'), ('f6-content.html', 'f6-content.html'), ('f6-vue.html', 'f6-vue.html'), ), default='f6-content.html') tags = ClusterTaggableManager(through=ContentTag, blank=True) def get_template(self, request, *args, **kwargs): template_name = request.GET.get('template', self.template_filename) return '{}/{}'.format(self.__class__._meta.app_label, template_name) promote_panels = Page.promote_panels + [ FieldPanel('date'), FieldPanel('tags') ] content_panels = Page.content_panels + [ StreamFieldPanel('body'), ] settings_panels = Page.settings_panels + [FieldPanel('template_filename')] search_fields = Page.search_fields + [ index.SearchField('body'), index.FilterField('url_path'), ] def serve(self, request): if 'draft' in request.GET: return HttpResponseRedirect('/admin/pages/{}/view_draft/'.format( self.pk)) response = super(Content, self).serve(request) if 'embed' in request.GET: with open( os.path.join(settings.MEDIA_ROOT, 'images', self.slug + '.html')) as output: output.write(response.content) return response class Meta: ordering = ('date', )
class EntryPage(Page, Entry): # Search search_fields = Page.search_fields + ( index.SearchField('body'), index.SearchField('excerpt'), index.FilterField('page_ptr_id') ) # Panels content_panels = [ MultiFieldPanel([ FieldPanel('title', classname="title"), ImageChooserPanel('header_image'), FieldPanel('body', classname="full"), FieldPanel('excerpt', classname="full"), ], heading=_("Content")), MultiFieldPanel([ FieldPanel('tags'), InlinePanel('entry_categories', label=_("Categories")), InlinePanel('related_entrypage_from', label=_("Related Entries")), ], heading=_("Metadata")), ] + getattr(Entry, 'content_panels', []) promote_panels = Page.promote_panels + getattr(Entry, 'promote_panels', []) settings_panels = Page.settings_panels + [ FieldPanel('date'), FieldPanel('owner'), ] + getattr(Entry, 'settings_panels', []) # Parent and child settings parent_page_types = ['puput.BlogPage'] subpage_types = [] @property def blog_page(self): return BlogPage.objects.ancestor_of(self).first() @property def related(self): return [related.entrypage_to for related in self.related_entrypage_from.all()] @property def has_related(self): return self.related_entrypage_from.count() > 0 def get_context(self, request, *args, **kwargs): context = super(EntryPage, self).get_context(request, *args, **kwargs) context['blog_page'] = self.blog_page return context class Meta: verbose_name = _('Entry') verbose_name_plural = _('Entries')
class Author(index.Indexed, models.Model): name = models.CharField(max_length=255) date_of_birth = models.DateField(null=True) search_fields = [ index.SearchField('name'), index.FilterField('date_of_birth'), ] def __str__(self): return self.name
class ProgrammingGuide(Book): programming_language = models.CharField(max_length=255, choices=[ ('py', "Python"), ('js', "Javascript"), ('rs', "Rust"), ]) search_fields = Book.search_fields + [ index.SearchField('get_programming_language_display'), index.FilterField('programming_language'), ]
class ContentArticle(Page): template = 'articles/article.html' date = models.DateField() # Each block will show up when adding elements to a page in the CMS body = StreamField([ ('paragraph', blocks.RichTextBlock(icon='edit', template='wagtail_blocks/paragraph.html')), ('image', ImageChooserBlock(icon='image', template='wagtail_blocks/image.html')), ('full_width_image', ImageChooserBlock(icon='image', template='wagtail_blocks/full_width_image.html')), ]) # We want to be able to tag articles with certain categories tags = ClusterTaggableManager(through=ArticleTag, blank=True) image = models.ForeignKey("wagtailimages.Image", null=True, blank=True, on_delete=models.SET_NULL, related_name="+") author = models.CharField(max_length=200, null=True, blank=True) search_fields = Page.search_fields + [ index.FilterField('title'), index.FilterField('author'), index.SearchField('body'), index.FilterField('date'), ] content_panels = Page.content_panels + [ FieldPanel('date'), FieldPanel('tags'), FieldPanel('author'), StreamFieldPanel('body'), InlinePanel('related_links', label="Related links"), ]
class AbstractGiphy(CollectionMember, index.Indexed, models.Model): title = models.CharField(max_length=255, verbose_name=_('title')) file = models.FileField( verbose_name=_('file'), upload_to=get_upload_to, ) created_at = models.DateTimeField(verbose_name=_('created at'), auto_now_add=True, db_index=True) uploaded_by_user = models.ForeignKey( settings.AUTH_USER_MODEL, verbose_name=_('uploaded by user'), null=True, blank=True, editable=False, on_delete=models.SET_NULL ) tags = TaggableManager(help_text=None, blank=True, verbose_name=_('tags')) file_size = models.PositiveIntegerField(null=True, editable=False) def get_file_size(self): if self.file_size is None: try: self.file_size = self.file.size except OSError: # File doesn't exist return self.save(update_fields=['file_size']) return self.file_size def get_upload_to(self, filename): folder_name = 'giphy' filename = self.file.field.storage.get_valid_name(filename) created_at = self.file.created_at return os.path.join(folder_name, '{y}/{m}/{d}/{filename}'.format(**{ 'y': created_at.year, 'm': created_at.month, 'd': created_at.day, 'filename': filename })) def __str__(self): return self.title search_fields = CollectionMember.search_fields + [ index.SearchField('title', partial_match=True, boost=10), index.RelatedFields('tags', [ index.SearchField('name', partial_match=True, boost=10), ]), index.FilterField('uploaded_by_user'), ] class Meta: abstract = True