models.py 6.9 KB

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