models.py 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. from __future__ import unicode_literals
  2. from django.db import models
  3. from modelcluster.fields import ParentalKey
  4. from modelcluster.models import ClusterableModel
  5. from wagtail.contrib.modeladmin.options import (
  6. ModelAdmin, ModelAdminGroup, modeladmin_register)
  7. from wagtail.wagtailadmin.edit_handlers import (
  8. FieldPanel, FieldRowPanel, InlinePanel, MultiFieldPanel,
  9. PageChooserPanel, StreamFieldPanel,
  10. )
  11. from wagtail.wagtailcore.fields import RichTextField, StreamField
  12. from wagtail.wagtailcore.models import Collection, Orderable, Page
  13. from wagtail.wagtailforms.models import AbstractEmailForm, AbstractFormField
  14. from wagtail.wagtailimages.edit_handlers import ImageChooserPanel
  15. from wagtail.wagtailsearch import index
  16. from wagtail.wagtailsnippets.models import register_snippet
  17. from .blocks import BaseStreamBlock
  18. @register_snippet
  19. class People(ClusterableModel):
  20. """
  21. `People` snippets are secondary content objects that do not require their
  22. own full webpage to render.
  23. """
  24. first_name = models.CharField("First name", max_length=254)
  25. last_name = models.CharField("Last name", max_length=254)
  26. job_title = models.CharField("Job title", max_length=254)
  27. image = models.ForeignKey(
  28. 'wagtailimages.Image',
  29. null=True,
  30. blank=True,
  31. on_delete=models.SET_NULL,
  32. related_name='+'
  33. )
  34. panels = [
  35. FieldPanel('first_name', classname="col6"),
  36. FieldPanel('last_name', classname="col6"),
  37. FieldPanel('job_title'),
  38. ImageChooserPanel('image')
  39. ]
  40. search_fields = Page.search_fields + [
  41. index.SearchField('first_name'),
  42. index.SearchField('last_name'),
  43. ]
  44. @property
  45. def thumb_image(self):
  46. # fail silently if there is no profile pic or the rendition file can't
  47. # be found. Note @richbrennan worked out how to do this...
  48. try:
  49. return self.image.get_rendition('fill-50x50').img_tag()
  50. except:
  51. return ''
  52. def __str__(self):
  53. return '{} {}'.format(self.first_name, self.last_name)
  54. class Meta:
  55. verbose_name = 'Person'
  56. verbose_name_plural = 'People'
  57. @register_snippet
  58. class FooterText(models.Model):
  59. """
  60. This provides editable text for the site footer
  61. """
  62. body = RichTextField()
  63. panels = [
  64. FieldPanel('body'),
  65. ]
  66. def __str__(self):
  67. return "Footer text"
  68. class Meta:
  69. verbose_name_plural = 'Footer Text'
  70. class AboutLocationRelationship(Orderable, models.Model):
  71. """
  72. This defines the relationship between the `LocationPage` within the `locations`
  73. app and the About page below allowing us to add locations to the about
  74. section.
  75. """
  76. page = ParentalKey(
  77. 'AboutPage', related_name='location_about_relationship'
  78. )
  79. locations = models.ForeignKey(
  80. 'locations.LocationPage', related_name='about_location_relationship'
  81. )
  82. panels = [
  83. PageChooserPanel('locations')
  84. ]
  85. class AboutPage(Page):
  86. """
  87. The About Page
  88. """
  89. image = models.ForeignKey(
  90. 'wagtailimages.Image',
  91. null=True,
  92. blank=True,
  93. on_delete=models.SET_NULL,
  94. related_name='+',
  95. help_text='Location image'
  96. )
  97. body = StreamField(
  98. BaseStreamBlock(), verbose_name="About page detail", blank=True
  99. )
  100. # We've defined the StreamBlock() within blocks.py that we've imported on
  101. # line 12. Defining it in a different file gives us consistency across the
  102. # site, though StreamFields _can_ be created on a per model basis if you
  103. # have a use case for it
  104. content_panels = Page.content_panels + [
  105. ImageChooserPanel('image'),
  106. StreamFieldPanel('body'),
  107. InlinePanel(
  108. 'location_about_relationship',
  109. label='Locations',
  110. min_num=None
  111. ),
  112. ]
  113. # parent_page_types = [
  114. # 'home.HomePage'
  115. # ]
  116. # Defining what content type can sit under the parent
  117. # The empty array means that no children can be placed under the
  118. # LocationPage page model
  119. subpage_types = []
  120. # api_fields = ['image', 'body']
  121. class HomePage(Page):
  122. """
  123. The Home Page
  124. """
  125. image = models.ForeignKey(
  126. 'wagtailimages.Image',
  127. null=True,
  128. blank=True,
  129. on_delete=models.SET_NULL,
  130. related_name='+',
  131. help_text='Location image'
  132. )
  133. body = StreamField(
  134. BaseStreamBlock(), verbose_name="Home page detail", blank=True
  135. )
  136. content_panels = Page.content_panels + [
  137. ImageChooserPanel('image'),
  138. StreamFieldPanel('body'),
  139. ]
  140. def __str__(self):
  141. return self.title
  142. class GalleryPage(Page):
  143. """
  144. This is a page to list all the locations on the site
  145. """
  146. choices = models.ForeignKey(
  147. Collection,
  148. limit_choices_to=~models.Q(name__in=['Root']),
  149. null=True,
  150. blank=True,
  151. on_delete=models.SET_NULL,
  152. )
  153. image = models.ForeignKey(
  154. 'wagtailimages.Image',
  155. null=True,
  156. blank=True,
  157. on_delete=models.SET_NULL,
  158. related_name='+',
  159. help_text='Location listing image'
  160. )
  161. introduction = models.TextField(
  162. help_text='Text to describe the index page',
  163. blank=True)
  164. content_panels = Page.content_panels + [
  165. FieldPanel('choices'),
  166. ImageChooserPanel('image'),
  167. FieldPanel('introduction')
  168. ]
  169. # parent_page_types = [
  170. # 'home.HomePage'
  171. # ]
  172. # Defining what content type can sit under the parent. Since it's a blank
  173. # array no subpage can be added
  174. subpage_types = [
  175. ]
  176. # api_fields = ['introduction']
  177. class FormField(AbstractFormField):
  178. page = ParentalKey('FormPage', related_name='form_fields')
  179. class FormPage(AbstractEmailForm):
  180. header_image = models.ForeignKey(
  181. 'wagtailimages.Image',
  182. null=True,
  183. blank=True,
  184. on_delete=models.SET_NULL,
  185. related_name='+'
  186. )
  187. body = StreamField(BaseStreamBlock())
  188. thank_you_text = RichTextField(blank=True)
  189. content_panels = AbstractEmailForm.content_panels + [
  190. ImageChooserPanel('header_image'),
  191. StreamFieldPanel('body'),
  192. InlinePanel('form_fields', label="Form fields"),
  193. FieldPanel('thank_you_text', classname="full"),
  194. MultiFieldPanel([
  195. FieldRowPanel([
  196. FieldPanel('from_address', classname="col6"),
  197. FieldPanel('to_address', classname="col6"),
  198. ]),
  199. FieldPanel('subject'),
  200. ], "Email"),
  201. ]
  202. class PeopleModelAdmin(ModelAdmin):
  203. model = People
  204. menu_label = 'People' # ditch this to use verbose_name_plural from model
  205. menu_icon = 'fa-people' # change as required
  206. list_display = ('first_name', 'last_name', 'job_title', 'thumb_image')
  207. class MyModelAdminGroup(ModelAdminGroup):
  208. menu_label = 'WagtailBakery'
  209. menu_icon = 'folder-open-inverse' # change as required
  210. menu_order = 200 # will put in 3rd place (000 being 1st, 100 2nd)
  211. items = (PeopleModelAdmin,)
  212. # When using a ModelAdminGroup class to group several ModelAdmin classes together,
  213. # you only need to register the ModelAdminGroup class with Wagtail:
  214. modeladmin_register(MyModelAdminGroup)