models.py 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. from django import forms
  2. from django.db import models
  3. from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
  4. from modelcluster.fields import ParentalManyToManyField
  5. from wagtail.wagtailadmin.edit_handlers import (
  6. FieldPanel, MultiFieldPanel, StreamFieldPanel
  7. )
  8. from wagtail.wagtailcore.fields import StreamField
  9. from wagtail.wagtailcore.models import Page
  10. from wagtail.wagtailsearch import index
  11. from wagtail.wagtailsnippets.models import register_snippet
  12. from bakerydemo.base.blocks import BaseStreamBlock
  13. from bakerydemo.base.models import BasePageFieldsMixin
  14. @register_snippet
  15. class Country(models.Model):
  16. """
  17. Standard Django model to store set of countries of origin.
  18. Exposed in the Wagtail admin via Snippets.
  19. """
  20. title = models.CharField(max_length=100)
  21. def __str__(self):
  22. return self.title
  23. class Meta:
  24. verbose_name_plural = "Countries of Origin"
  25. @register_snippet
  26. class BreadIngredient(models.Model):
  27. """
  28. Standard Django model used as a Snippet in the BreadPage model.
  29. Demonstrates ManyToMany relationship.
  30. """
  31. name = models.CharField(max_length=255)
  32. panels = [
  33. FieldPanel('name'),
  34. ]
  35. def __str__(self):
  36. return self.name
  37. class Meta:
  38. verbose_name_plural = 'Bread ingredients'
  39. @register_snippet
  40. class BreadType(models.Model):
  41. """
  42. Standard Django model used as a Snippet in the BreadPage model.
  43. """
  44. title = models.CharField(max_length=255)
  45. panels = [
  46. FieldPanel('title'),
  47. ]
  48. def __str__(self):
  49. return self.title
  50. class Meta:
  51. verbose_name_plural = "Bread types"
  52. class BreadPage(BasePageFieldsMixin, Page):
  53. """
  54. Detail view for a specific bread
  55. """
  56. origin = models.ForeignKey(
  57. Country,
  58. on_delete=models.SET_NULL,
  59. null=True,
  60. blank=True,
  61. )
  62. body = StreamField(
  63. BaseStreamBlock(), verbose_name="Describe the bread", blank=True
  64. )
  65. bread_type = models.ForeignKey(
  66. 'breads.BreadType',
  67. null=True,
  68. blank=True,
  69. on_delete=models.SET_NULL,
  70. related_name='+'
  71. )
  72. ingredients = ParentalManyToManyField('BreadIngredient', blank=True)
  73. content_panels = BasePageFieldsMixin.content_panels + [
  74. StreamFieldPanel('body'),
  75. FieldPanel('origin'),
  76. FieldPanel('bread_type'),
  77. MultiFieldPanel(
  78. [
  79. FieldPanel(
  80. 'ingredients',
  81. widget=forms.CheckboxSelectMultiple,
  82. ),
  83. ],
  84. heading="Additional Metadata",
  85. classname="collapsible collapsed"
  86. ),
  87. ]
  88. search_fields = Page.search_fields + [
  89. index.SearchField('title'),
  90. index.SearchField('body'),
  91. ]
  92. parent_page_types = ['BreadsIndexPage']
  93. api_fields = ['title', 'bread_type', 'origin', 'image']
  94. class BreadsIndexPage(BasePageFieldsMixin, Page):
  95. """
  96. Index page for breads. We don't have any fields within our model but we need
  97. to alter the page model's context to return the child page objects - the
  98. BreadPage - so that it works as an index page
  99. """
  100. subpage_types = ['BreadPage']
  101. def get_breads(self):
  102. return BreadPage.objects.live().descendant_of(
  103. self).order_by('-first_published_at')
  104. def children(self):
  105. return self.get_children().specific().live()
  106. def paginate(self, request, *args):
  107. page = request.GET.get('page')
  108. paginator = Paginator(self.get_breads(), 12)
  109. try:
  110. pages = paginator.page(page)
  111. except PageNotAnInteger:
  112. pages = paginator.page(1)
  113. except EmptyPage:
  114. pages = paginator.page(paginator.num_pages)
  115. return pages
  116. def get_context(self, request):
  117. context = super(BreadsIndexPage, self).get_context(request)
  118. breads = self.paginate(request, self.get_breads())
  119. context['breads'] = breads
  120. return context