models.py 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. from datetime import datetime
  2. from django.conf import settings
  3. from django.core.validators import RegexValidator
  4. from django.db import models
  5. from modelcluster.fields import ParentalKey
  6. from wagtail.wagtailadmin.edit_handlers import FieldPanel, InlinePanel
  7. from wagtail.wagtailcore.models import Orderable, Page
  8. from wagtail.wagtailsearch import index
  9. from wagtail.wagtailimages.edit_handlers import ImageChooserPanel
  10. from bakerydemo.base.models import BasePageFieldsMixin
  11. from bakerydemo.locations.choices import DAY_CHOICES
  12. class OperatingHours(models.Model):
  13. """
  14. Django model to capture operating hours for a Location
  15. """
  16. day = models.CharField(
  17. max_length=4,
  18. choices=DAY_CHOICES,
  19. default='MON'
  20. )
  21. opening_time = models.TimeField(
  22. blank=True,
  23. null=True)
  24. closing_time = models.TimeField(
  25. blank=True,
  26. null=True)
  27. closed = models.BooleanField(
  28. "Closed?",
  29. blank=True,
  30. help_text='Tick if location is closed on this day'
  31. )
  32. panels = [
  33. FieldPanel('day'),
  34. FieldPanel('opening_time'),
  35. FieldPanel('closing_time'),
  36. FieldPanel('closed'),
  37. ]
  38. class Meta:
  39. abstract = True
  40. def __str__(self):
  41. if self.opening_time:
  42. opening = self.opening_time.strftime('%H:%M')
  43. else:
  44. opening = '--'
  45. if self.closing_time:
  46. closed = self.opening_time.strftime('%H:%M')
  47. else:
  48. closed = '--'
  49. return '{}: {} - {} {}'.format(
  50. self.day,
  51. opening,
  52. closed,
  53. settings.TIME_ZONE
  54. )
  55. class LocationOperatingHours(Orderable, OperatingHours):
  56. """
  57. Operating Hours entry for a Location
  58. """
  59. location = ParentalKey(
  60. 'LocationPage',
  61. related_name='hours_of_operation'
  62. )
  63. class LocationsIndexPage(BasePageFieldsMixin, Page):
  64. """
  65. Index page for locations
  66. """
  67. subpage_types = ['LocationPage']
  68. def children(self):
  69. return self.get_children().specific().live()
  70. def get_context(self, request):
  71. context = super(LocationsIndexPage, self).get_context(request)
  72. context['locations'] = LocationPage.objects.descendant_of(
  73. self).live().order_by(
  74. 'title')
  75. return context
  76. content_panels = Page.content_panels + [
  77. FieldPanel('introduction', classname="full"),
  78. ImageChooserPanel('image'),
  79. ]
  80. class LocationPage(BasePageFieldsMixin, Page):
  81. """
  82. Detail for a specific bakery location.
  83. """
  84. address = models.TextField()
  85. lat_long = models.CharField(
  86. max_length=36,
  87. help_text="Comma separated lat/long. (Ex. 64.144367, -21.939182) \
  88. Right click Google Maps and select 'What\'s Here'",
  89. validators=[
  90. RegexValidator(
  91. regex='^(\-?\d+(\.\d+)?),\s*(\-?\d+(\.\d+)?)$',
  92. message='Lat Long must be a comma-separated numeric lat and long',
  93. code='invalid_lat_long'
  94. ),
  95. ]
  96. )
  97. # Search index configuration
  98. search_fields = Page.search_fields + [
  99. index.SearchField('address'),
  100. index.SearchField('body'),
  101. ]
  102. # Editor panels configuration
  103. content_panels = BasePageFieldsMixin.content_panels + [
  104. FieldPanel('address', classname="full"),
  105. FieldPanel('lat_long'),
  106. InlinePanel('hours_of_operation', label="Hours of Operation"),
  107. ]
  108. def __str__(self):
  109. return self.title
  110. @property
  111. def operating_hours(self):
  112. hours = self.hours_of_operation.all()
  113. return hours
  114. def is_open(self):
  115. # Determines if the location is currently open
  116. now = datetime.now()
  117. current_time = now.time()
  118. current_day = now.strftime('%a').upper()
  119. try:
  120. self.operating_hours.get(
  121. day=current_day,
  122. opening_time__lte=current_time,
  123. closing_time__gte=current_time
  124. )
  125. return True
  126. except LocationOperatingHours.DoesNotExist:
  127. return False
  128. def get_context(self, request):
  129. context = super(LocationPage, self).get_context(request)
  130. context['lat'] = self.lat_long.split(",")[0]
  131. context['long'] = self.lat_long.split(",")[1]
  132. return context
  133. parent_page_types = ['LocationsIndexPage']