models.py 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. from __future__ import unicode_literals
  2. from django.db import models
  3. from django.shortcuts import get_list_or_404, get_object_or_404, render
  4. from modelcluster.fields import ParentalKey
  5. from modelcluster.contrib.taggit import ClusterTaggableManager
  6. from taggit.models import Tag, TaggedItemBase
  7. from wagtail.contrib.wagtailroutablepage.models import RoutablePageMixin, route
  8. from wagtail.wagtailadmin.edit_handlers import (
  9. FieldPanel,
  10. InlinePanel,
  11. StreamFieldPanel,
  12. )
  13. from wagtail.wagtailimages.edit_handlers import ImageChooserPanel
  14. from wagtail.wagtailcore.fields import StreamField
  15. from wagtail.wagtailcore.models import Page, Orderable
  16. from wagtail.wagtailsnippets.edit_handlers import SnippetChooserPanel
  17. from bakerydemo.base.blocks import BaseStreamBlock
  18. class BlogPeopleRelationship(Orderable, models.Model):
  19. '''
  20. This defines the relationship between the `People` within the `base`
  21. app and the BlogPage below allowing us to add people to a BlogPage.
  22. '''
  23. page = ParentalKey(
  24. 'BlogPage', related_name='blog_person_relationship'
  25. )
  26. people = models.ForeignKey(
  27. 'base.People', related_name='person_blog_relationship'
  28. )
  29. panels = [
  30. SnippetChooserPanel('people')
  31. ]
  32. class BlogPageTag(TaggedItemBase):
  33. content_object = ParentalKey('BlogPage', related_name='tagged_items')
  34. class BlogPage(Page):
  35. '''
  36. A Blog Page (Post)
  37. '''
  38. image = models.ForeignKey(
  39. 'wagtailimages.Image',
  40. null=True,
  41. blank=True,
  42. on_delete=models.SET_NULL,
  43. related_name='+',
  44. help_text='Location image'
  45. )
  46. tags = ClusterTaggableManager(through=BlogPageTag, blank=True)
  47. date_published = models.DateField("Date article published", blank=True, null=True)
  48. body = StreamField(
  49. BaseStreamBlock(), verbose_name="Blog post", blank=True
  50. )
  51. content_panels = Page.content_panels + [
  52. ImageChooserPanel('image'),
  53. StreamFieldPanel('body'),
  54. FieldPanel('date_published'),
  55. InlinePanel(
  56. 'blog_person_relationship', label="Author(s)",
  57. panels=None, min_num=1),
  58. FieldPanel('tags'),
  59. ]
  60. def authors(self):
  61. '''
  62. Returns the BlogPage's related People
  63. '''
  64. authors = [
  65. n.people for n in self.blog_person_relationship.all()
  66. ]
  67. return authors
  68. @property
  69. def get_tags(self):
  70. '''
  71. Returns the BlogPage's related list of Tags.
  72. Each Tag is modified to include a url attribute
  73. '''
  74. tags = self.tags.all()
  75. for tag in tags:
  76. tag.url = '/'+'/'.join(s.strip('/') for s in [
  77. self.get_parent().url,
  78. 'tags',
  79. tag.slug
  80. ])
  81. return tags
  82. parent_page_types = ['BlogIndexPage']
  83. # Defining what content type can sit under the parent
  84. # The empty array means that no children can be placed under the
  85. # LocationPage page model
  86. subpage_types = []
  87. # api_fields = ['image', 'body']
  88. class BlogIndexPage(RoutablePageMixin, Page):
  89. '''
  90. Index page for blogs.
  91. We need to alter the page model's context to return the child page objects - the
  92. BlogPage - so that it works as an index page
  93. The RoutablePageMixin is used to allow for a custom sub-URL
  94. '''
  95. image = models.ForeignKey(
  96. 'wagtailimages.Image',
  97. null=True,
  98. blank=True,
  99. on_delete=models.SET_NULL,
  100. related_name='+',
  101. help_text='Location listing image'
  102. )
  103. introduction = models.TextField(
  104. help_text='Text to describe the index page',
  105. blank=True)
  106. content_panels = Page.content_panels + [
  107. ImageChooserPanel('image'),
  108. FieldPanel('introduction')
  109. ]
  110. # parent_page_types = [
  111. # 'home.HomePage'
  112. # ]
  113. # Defining what content type can sit under the parent. Since it's a blank
  114. # array no subpage can be added
  115. subpage_types = ['BlogPage']
  116. def get_context(self, request):
  117. context = super(BlogIndexPage, self).get_context(request)
  118. context['blogs'] = BlogPage.objects.descendant_of(
  119. self).live().order_by(
  120. '-first_published_at')
  121. return context
  122. @route('^tags/(\w+)/$', name='tag_archive')
  123. def tag_archive(self, request, tag=None):
  124. '''
  125. A Custom view that utilizes Tags. This view will
  126. return all related BlogPages for a given Tag.
  127. '''
  128. tag = get_object_or_404(Tag, slug=tag)
  129. blogs = get_list_or_404(
  130. BlogPage.objects.filter(tags=tag).live().descendant_of(self)
  131. )
  132. context = {
  133. 'title': 'Posts tagged with: {}'.format(tag.name),
  134. 'blogs': blogs
  135. }
  136. return render(request, 'blog/blog_index_page.html', context)
  137. # api_fields = ['introduction']