models.py 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. from django.core.paginator import EmptyPage, PageNotAnInteger, Paginator
  2. from django.db import models
  3. from wagtail.admin.panels import FieldPanel
  4. from wagtail.api import APIField
  5. from wagtail.blocks import ChoiceBlock, StructBlock, StructValue, URLBlock
  6. from wagtail.fields import StreamField
  7. from wagtail.models import Page
  8. from wagtail.search import index
  9. from bakerydemo.base.blocks import BaseStreamBlock
  10. from ..breads.models import Country
  11. class SocialMediaValue(StructValue):
  12. def get_platform_label(self):
  13. return dict(self.block.child_blocks["platform"].field.choices).get(
  14. self["platform"]
  15. )
  16. class SocialMediaBlock(StructBlock):
  17. """
  18. Block for social media links
  19. """
  20. platform = ChoiceBlock(
  21. choices=[
  22. ("github", "GitHub"),
  23. ("twitter", "Twitter/X"),
  24. ("linkedin", "LinkedIn"),
  25. ("instagram", "Instagram"),
  26. ("facebook", "Facebook"),
  27. ("mastodon", "Mastodon"),
  28. ("website", "Personal Website"),
  29. ],
  30. help_text="Select the social media platform",
  31. )
  32. url = URLBlock(
  33. label="URL",
  34. help_text="Full URL to your profile (e.g., https://github.com/username)",
  35. )
  36. class Meta:
  37. icon = "link"
  38. label = "Social Media Link"
  39. value_class = SocialMediaValue
  40. class PersonPage(Page):
  41. """
  42. Detail view for a specific person
  43. """
  44. introduction = models.TextField(help_text="Text to describe the page", blank=True)
  45. image = models.ForeignKey(
  46. "wagtailimages.Image",
  47. null=True,
  48. blank=True,
  49. on_delete=models.SET_NULL,
  50. related_name="+",
  51. help_text="Landscape mode only; horizontal width between 1000px and 3000px.",
  52. )
  53. body = StreamField(BaseStreamBlock(), verbose_name="Page body", blank=True)
  54. location = models.ForeignKey(
  55. Country,
  56. on_delete=models.SET_NULL,
  57. null=True,
  58. blank=True,
  59. )
  60. social_links = StreamField(
  61. [("social", SocialMediaBlock())],
  62. blank=True,
  63. help_text="Add social media profiles",
  64. )
  65. content_panels = Page.content_panels + [
  66. FieldPanel("introduction"),
  67. FieldPanel("image"),
  68. FieldPanel("location"),
  69. FieldPanel("body"),
  70. FieldPanel("social_links"),
  71. ]
  72. search_fields = Page.search_fields + [
  73. index.SearchField("introduction"),
  74. index.SearchField("body"),
  75. ]
  76. parent_page_types = ["PeopleIndexPage"]
  77. api_fields = [
  78. APIField("introduction"),
  79. APIField("image"),
  80. APIField("body"),
  81. APIField("location"),
  82. APIField("social_links"),
  83. ]
  84. def get_context(self, request):
  85. context = super(PersonPage, self).get_context(request)
  86. platform_block = SocialMediaBlock().child_blocks["platform"]
  87. platform_labels = dict(platform_block.field.choices)
  88. social_links = [
  89. {
  90. "platform": link.value["platform"],
  91. "label": platform_labels.get(
  92. link.value["platform"], link.value["platform"]
  93. ),
  94. "url": link.value["url"],
  95. }
  96. for link in (self.social_links or [])
  97. ]
  98. context["social_links"] = social_links
  99. return context
  100. class PeopleIndexPage(Page):
  101. """
  102. Index page for people.
  103. Lists all People objects with pagination.
  104. """
  105. introduction = models.TextField(help_text="Text to describe the page", blank=True)
  106. image = models.ForeignKey(
  107. "wagtailimages.Image",
  108. null=True,
  109. blank=True,
  110. on_delete=models.SET_NULL,
  111. related_name="+",
  112. help_text="Landscape mode only; horizontal width between 1000px and 3000px.",
  113. )
  114. content_panels = Page.content_panels + [
  115. FieldPanel("introduction"),
  116. FieldPanel("image"),
  117. ]
  118. # Can only have PersonPage children
  119. subpage_types = ["PersonPage"]
  120. api_fields = [
  121. APIField("introduction"),
  122. APIField("image"),
  123. ]
  124. # Returns a queryset of PersonPage objects that are live, that are direct
  125. # descendants of this index page with most recent first
  126. def get_people(self):
  127. return (
  128. PersonPage.objects.live()
  129. .descendant_of(self)
  130. .order_by("-first_published_at")
  131. )
  132. # Allows child objects (e.g. PersonPage objects) to be accessible via the
  133. # template
  134. def children(self):
  135. return self.get_children().specific().live()
  136. # Pagination for the index page
  137. def paginate(self, request, *args):
  138. page = request.GET.get("page")
  139. paginator = Paginator(self.get_people(), 12)
  140. try:
  141. pages = paginator.page(page)
  142. except PageNotAnInteger:
  143. pages = paginator.page(1)
  144. except EmptyPage:
  145. pages = paginator.page(paginator.num_pages)
  146. return pages
  147. # Returns the above to the get_context method that is used to populate the
  148. # template
  149. def get_context(self, request):
  150. context = super(PeopleIndexPage, self).get_context(request)
  151. # PersonPage objects (get_people) are passed through pagination
  152. people = self.paginate(request, self.get_people())
  153. context["people"] = people
  154. return context