models.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  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.wagtailadmin.edit_handlers import (
  6. FieldPanel,
  7. FieldRowPanel,
  8. InlinePanel,
  9. MultiFieldPanel,
  10. PageChooserPanel,
  11. StreamFieldPanel,
  12. )
  13. from wagtail.wagtailcore.fields import RichTextField, StreamField
  14. from wagtail.wagtailcore.models import Collection, Page
  15. from wagtail.wagtailforms.models import AbstractEmailForm, AbstractFormField
  16. from wagtail.wagtailimages.edit_handlers import ImageChooserPanel
  17. from wagtail.wagtailsearch import index
  18. from wagtail.wagtailsnippets.models import register_snippet
  19. from .blocks import BaseStreamBlock
  20. @register_snippet
  21. class People(ClusterableModel):
  22. """
  23. A Django model to store People objects.
  24. It uses the `@register_snippet` decorator to allow it to be accessible
  25. as via the Snippets UI (e.g. /admin/snippets/base/people/)
  26. `People` uses the `ClusterableModel`, which allows the relationship to another
  27. model (e.g. a PageModel) to be stored independently of the database. This
  28. allows us to preview foreignKey relationships without first saving the parent
  29. https://github.com/wagtail/django-modelcluster
  30. """
  31. first_name = models.CharField("First name", max_length=254)
  32. last_name = models.CharField("Last name", max_length=254)
  33. job_title = models.CharField("Job title", max_length=254)
  34. image = models.ForeignKey(
  35. 'wagtailimages.Image',
  36. null=True,
  37. blank=True,
  38. on_delete=models.SET_NULL,
  39. related_name='+'
  40. )
  41. panels = [
  42. FieldPanel('first_name', classname="col6"),
  43. FieldPanel('last_name', classname="col6"),
  44. FieldPanel('job_title'),
  45. ImageChooserPanel('image')
  46. ]
  47. search_fields = Page.search_fields + [
  48. index.SearchField('first_name'),
  49. index.SearchField('last_name'),
  50. ]
  51. @property
  52. def thumb_image(self):
  53. # Returns an empty string if there is no profile pic or the rendition
  54. # file can't be found.
  55. try:
  56. return self.image.get_rendition('fill-50x50').img_tag()
  57. except:
  58. return ''
  59. def __str__(self):
  60. return '{} {}'.format(self.first_name, self.last_name)
  61. class Meta:
  62. verbose_name = 'Person'
  63. verbose_name_plural = 'People'
  64. @register_snippet
  65. class FooterText(models.Model):
  66. """
  67. This provides editable text for the site footer. Again it uses the decorator
  68. `register_snippet` to allow it to be accessible via the admin. It is made
  69. accessible on the template via a template tag defined in base/templatetags/
  70. navigation_tags.py
  71. """
  72. body = RichTextField()
  73. panels = [
  74. FieldPanel('body'),
  75. ]
  76. def __str__(self):
  77. return "Footer text"
  78. class Meta:
  79. verbose_name_plural = 'Footer Text'
  80. class StandardPage(Page):
  81. """
  82. A generic content page. On this demo site we use it for an about page but
  83. could be used for any type of page content.
  84. """
  85. introduction = models.TextField(
  86. help_text='Text to describe the page',
  87. blank=True)
  88. image = models.ForeignKey(
  89. 'wagtailimages.Image',
  90. null=True,
  91. blank=True,
  92. on_delete=models.SET_NULL,
  93. related_name='+',
  94. help_text='Landscape mode only; horizontal width between 1000px and 3000px.'
  95. )
  96. body = StreamField(
  97. BaseStreamBlock(), verbose_name="Page body", blank=True
  98. )
  99. content_panels = Page.content_panels + [
  100. FieldPanel('introduction', classname="full"),
  101. StreamFieldPanel('body'),
  102. ImageChooserPanel('image'),
  103. ]
  104. class HomePage(Page):
  105. """
  106. The Home Page. This looks slightly more complicated than it is. You can
  107. see if you visit your site and edit the homepage that it is split between
  108. a:
  109. - Hero area
  110. - Body area
  111. - A promotional area
  112. - Moveable featured site sections
  113. """
  114. # Hero section of HomePage
  115. image = models.ForeignKey(
  116. 'wagtailimages.Image',
  117. null=True,
  118. blank=True,
  119. on_delete=models.SET_NULL,
  120. related_name='+',
  121. help_text='Homepage image'
  122. )
  123. hero_text = models.CharField(
  124. max_length=255,
  125. help_text='Write an introduction for the bakery'
  126. )
  127. hero_cta = models.CharField(
  128. verbose_name='Hero CTA',
  129. max_length=255,
  130. help_text='Text to display on Call to Action'
  131. )
  132. hero_cta_link = models.ForeignKey(
  133. 'wagtailcore.Page',
  134. null=True,
  135. blank=True,
  136. on_delete=models.SET_NULL,
  137. related_name='+',
  138. verbose_name='Hero CTA link',
  139. help_text='Choose a page to link to for the Call to Action'
  140. )
  141. # Body section of the HomePage
  142. body = StreamField(
  143. BaseStreamBlock(), verbose_name="Home content block", blank=True
  144. )
  145. # Promo section of the HomePage
  146. promo_image = models.ForeignKey(
  147. 'wagtailimages.Image',
  148. null=True,
  149. blank=True,
  150. on_delete=models.SET_NULL,
  151. related_name='+',
  152. help_text='Promo image'
  153. )
  154. promo_title = models.CharField(
  155. null=True,
  156. blank=True,
  157. max_length=255,
  158. help_text='Title to display above the promo copy'
  159. )
  160. promo_text = RichTextField(
  161. null=True,
  162. blank=True,
  163. help_text='Write some promotional copy'
  164. )
  165. # Featured sections on the HomePage
  166. # You will see on templates/base/home_page.html that these are treated
  167. # in different ways, and displayed in different areas of the page.
  168. # Each list their children items that we access via the children function
  169. # that we define on the individual Page models e.g. BlogIndexPage
  170. featured_section_1_title = models.CharField(
  171. null=True,
  172. blank=True,
  173. max_length=255,
  174. help_text='Title to display above the promo copy'
  175. )
  176. featured_section_1 = models.ForeignKey(
  177. 'wagtailcore.Page',
  178. null=True,
  179. blank=True,
  180. on_delete=models.SET_NULL,
  181. related_name='+',
  182. help_text='First featured section for the homepage. Will display up to '
  183. 'three child items.',
  184. verbose_name='Featured section 1'
  185. )
  186. featured_section_2_title = models.CharField(
  187. null=True,
  188. blank=True,
  189. max_length=255,
  190. help_text='Title to display above the promo copy'
  191. )
  192. featured_section_2 = models.ForeignKey(
  193. 'wagtailcore.Page',
  194. null=True,
  195. blank=True,
  196. on_delete=models.SET_NULL,
  197. related_name='+',
  198. help_text='Second featured section for the homepage. Will display up to '
  199. 'three child items.',
  200. verbose_name='Featured section 2'
  201. )
  202. featured_section_3_title = models.CharField(
  203. null=True,
  204. blank=True,
  205. max_length=255,
  206. help_text='Title to display above the promo copy'
  207. )
  208. featured_section_3 = models.ForeignKey(
  209. 'wagtailcore.Page',
  210. null=True,
  211. blank=True,
  212. on_delete=models.SET_NULL,
  213. related_name='+',
  214. help_text='Third featured section for the homepage. Will display up to '
  215. 'six child items.',
  216. verbose_name='Featured section 3'
  217. )
  218. content_panels = Page.content_panels + [
  219. MultiFieldPanel([
  220. ImageChooserPanel('image'),
  221. FieldPanel('hero_text', classname="full"),
  222. MultiFieldPanel([
  223. FieldPanel('hero_cta'),
  224. PageChooserPanel('hero_cta_link'),
  225. ])
  226. ], heading="Hero section"),
  227. MultiFieldPanel([
  228. ImageChooserPanel('promo_image'),
  229. FieldPanel('promo_title'),
  230. FieldPanel('promo_text'),
  231. ], heading="Promo section"),
  232. StreamFieldPanel('body'),
  233. MultiFieldPanel([
  234. MultiFieldPanel([
  235. FieldPanel('featured_section_1_title'),
  236. PageChooserPanel('featured_section_1'),
  237. ]),
  238. MultiFieldPanel([
  239. FieldPanel('featured_section_2_title'),
  240. PageChooserPanel('featured_section_2'),
  241. ]),
  242. MultiFieldPanel([
  243. FieldPanel('featured_section_3_title'),
  244. PageChooserPanel('featured_section_3'),
  245. ])
  246. ], heading="Featured homepage sections", classname="collapsible")
  247. ]
  248. def __str__(self):
  249. return self.title
  250. class GalleryPage(Page):
  251. """
  252. This is a page to list locations from the selected Collection. We use a Q
  253. object to list any Collection created (/admin/collections/) even if they
  254. contain no items. It's unlikely to be useful for many production settings
  255. but is intended to show the extensibility of aspect of Wagtail
  256. """
  257. introduction = models.TextField(
  258. help_text='Text to describe the page',
  259. blank=True)
  260. image = models.ForeignKey(
  261. 'wagtailimages.Image',
  262. null=True,
  263. blank=True,
  264. on_delete=models.SET_NULL,
  265. related_name='+',
  266. help_text='Landscape mode only; horizontal width between 1000px and 3000px.'
  267. )
  268. body = StreamField(
  269. BaseStreamBlock(), verbose_name="Page body", blank=True
  270. )
  271. collection = models.ForeignKey(
  272. Collection,
  273. limit_choices_to=~models.Q(name__in=['Root']),
  274. null=True,
  275. blank=True,
  276. on_delete=models.SET_NULL,
  277. help_text='Select the image collection for this gallery.'
  278. )
  279. content_panels = Page.content_panels + [
  280. FieldPanel('introduction', classname="full"),
  281. StreamFieldPanel('body'),
  282. ImageChooserPanel('image'),
  283. FieldPanel('collection'),
  284. ]
  285. # Defining what content type can sit under the parent. Since it's a blank
  286. # array no subpage can be added
  287. subpage_types = []
  288. class FormField(AbstractFormField):
  289. """
  290. Wagtailforms is a module to introduce simple forms on a Wagtail site. It
  291. isn't intended as a replacement to Django's form support but as a quick way
  292. to generate general purpose data-collection form without having to write
  293. code. We use it on the site for a contact form. You can read more about
  294. Wagtail forms at:
  295. http://docs.wagtail.io/en/v1.9/reference/contrib/forms/index.html
  296. """
  297. page = ParentalKey('FormPage', related_name='form_fields')
  298. class FormPage(AbstractEmailForm):
  299. image = models.ForeignKey(
  300. 'wagtailimages.Image',
  301. null=True,
  302. blank=True,
  303. on_delete=models.SET_NULL,
  304. related_name='+'
  305. )
  306. body = StreamField(BaseStreamBlock())
  307. thank_you_text = RichTextField(blank=True)
  308. # Note how we include the FormField object via an InlinePanel using the
  309. # related_name value
  310. content_panels = AbstractEmailForm.content_panels + [
  311. ImageChooserPanel('image'),
  312. StreamFieldPanel('body'),
  313. InlinePanel('form_fields', label="Form fields"),
  314. FieldPanel('thank_you_text', classname="full"),
  315. MultiFieldPanel([
  316. FieldRowPanel([
  317. FieldPanel('from_address', classname="col6"),
  318. FieldPanel('to_address', classname="col6"),
  319. ]),
  320. FieldPanel('subject'),
  321. ], "Email"),
  322. ]