models.py 4.5 KB

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