Add start/end time fields to CalendarEvent (#28) #29
@@ -165,10 +165,23 @@ class CalendarEventAdmin(admin.ModelAdmin):
|
|||||||
list_display = [
|
list_display = [
|
||||||
"event_name",
|
"event_name",
|
||||||
"start_date",
|
"start_date",
|
||||||
|
"start_time",
|
||||||
"end_date",
|
"end_date",
|
||||||
|
"end_time",
|
||||||
"coordinator_email",
|
"coordinator_email",
|
||||||
"event_link_name",
|
"event_link_name",
|
||||||
]
|
]
|
||||||
|
fields = [
|
||||||
|
"event_name",
|
||||||
|
"start_date",
|
||||||
|
"start_time",
|
||||||
|
"end_date",
|
||||||
|
"end_time",
|
||||||
|
"location_name",
|
||||||
|
"coordinator_email",
|
||||||
|
"event_link_name",
|
||||||
|
"event_url",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
class AddressModelAdmin(admin.ModelAdmin):
|
class AddressModelAdmin(admin.ModelAdmin):
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
# Generated by Django 6.0.7 on 2026-08-04 17:59
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('schasite', '0012_alter_payments_date'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='calendarevent',
|
||||||
|
name='end_time',
|
||||||
|
field=models.TimeField(blank=True, null=True),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='calendarevent',
|
||||||
|
name='start_time',
|
||||||
|
field=models.TimeField(blank=True, null=True),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -66,6 +66,8 @@ class CalendarEvent(TimeInfoBase):
|
|||||||
event_name = models.CharField(max_length=256)
|
event_name = models.CharField(max_length=256)
|
||||||
start_date = models.DateField(blank=True, null=True)
|
start_date = models.DateField(blank=True, null=True)
|
||||||
end_date = models.DateField(blank=True, null=True)
|
end_date = models.DateField(blank=True, null=True)
|
||||||
|
start_time = models.TimeField(blank=True, null=True)
|
||||||
|
end_time = models.TimeField(blank=True, null=True)
|
||||||
location_name = models.CharField(max_length=256, blank=True, null=True)
|
location_name = models.CharField(max_length=256, blank=True, null=True)
|
||||||
coordinator_email = models.EmailField(max_length=256, blank=True, null=True)
|
coordinator_email = models.EmailField(max_length=256, blank=True, null=True)
|
||||||
event_link_name = models.CharField(max_length=64, blank=True, null=True)
|
event_link_name = models.CharField(max_length=64, blank=True, null=True)
|
||||||
@@ -90,6 +92,19 @@ class CalendarEvent(TimeInfoBase):
|
|||||||
def no_date(self):
|
def no_date(self):
|
||||||
return not self.has_date()
|
return not self.has_date()
|
||||||
|
|
||||||
|
def time_range_display(self):
|
||||||
|
"""Format start/end times for templates, e.g. '11:00 AM - 3:00 PM'."""
|
||||||
|
from django.utils.formats import time_format
|
||||||
|
|
||||||
|
if not self.start_time and not self.end_time:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
start = time_format(self.start_time, "g:i A") if self.start_time else ""
|
||||||
|
end = time_format(self.end_time, "g:i A") if self.end_time else ""
|
||||||
|
if start and end:
|
||||||
|
return f"{start} - {end}"
|
||||||
|
return start or end
|
||||||
|
|
||||||
|
|
||||||
class CalendarEventAddressModel(TimeInfoBase):
|
class CalendarEventAddressModel(TimeInfoBase):
|
||||||
calendar_event = models.OneToOneField(CalendarEvent, on_delete=models.CASCADE)
|
calendar_event = models.OneToOneField(CalendarEvent, on_delete=models.CASCADE)
|
||||||
|
|||||||
@@ -23,6 +23,9 @@
|
|||||||
{% else %}
|
{% else %}
|
||||||
<p>Date: {{ event.start_date }} - {{ event.end_date }}</p>
|
<p>Date: {{ event.start_date }} - {{ event.end_date }}</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% if event.time_range_display %}
|
||||||
|
<p>Time: {{ event.time_range_display }}</p>
|
||||||
|
{% endif %}
|
||||||
<p>Location: {{ event.location_name }} - {{ event.calendareventaddressmodel }}</p>
|
<p>Location: {{ event.location_name }} - {{ event.calendareventaddressmodel }}</p>
|
||||||
{% if event.coordinator_email %}
|
{% if event.coordinator_email %}
|
||||||
<p>Coordinator: {{ event.coordinator_email }}</p>
|
<p>Coordinator: {{ event.coordinator_email }}</p>
|
||||||
@@ -44,6 +47,9 @@
|
|||||||
{% else %}
|
{% else %}
|
||||||
<p>Date: {{ event.start_date }} - {{ event.end_date }}</p>
|
<p>Date: {{ event.start_date }} - {{ event.end_date }}</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% if event.time_range_display %}
|
||||||
|
<p>Time: {{ event.time_range_display }}</p>
|
||||||
|
{% endif %}
|
||||||
<p>Location: {{ event.location_name }} - {{ event.calendareventaddressmodel }}</p>
|
<p>Location: {{ event.location_name }} - {{ event.calendareventaddressmodel }}</p>
|
||||||
{% if event.coordinator_email %}
|
{% if event.coordinator_email %}
|
||||||
<p>Coordinator: {{ event.coordinator_email }}</p>
|
<p>Coordinator: {{ event.coordinator_email }}</p>
|
||||||
|
|||||||
@@ -115,7 +115,9 @@
|
|||||||
<div class="col-md-8">
|
<div class="col-md-8">
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<p class="mb-1"><i class="bi bi-calendar-event text-success me-2"></i><strong>Date:</strong> {{ event.start_date }}</p>
|
<p class="mb-1"><i class="bi bi-calendar-event text-success me-2"></i><strong>Date:</strong> {{ event.start_date }}</p>
|
||||||
<p class="mb-1"><i class="bi bi-clock text-success me-2"></i><strong>Time:</strong> 11:00 AM - 3:00 PM</p>
|
{% if event.time_range_display %}
|
||||||
|
<p class="mb-1"><i class="bi bi-clock text-success me-2"></i><strong>Time:</strong> {{ event.time_range_display }}</p>
|
||||||
|
{% endif %}
|
||||||
<p class="mb-1"><i class="bi bi-geo-alt text-success me-2"></i><strong>Location:</strong> {{ event.location_name }}</p>
|
<p class="mb-1"><i class="bi bi-geo-alt text-success me-2"></i><strong>Location:</strong> {{ event.location_name }}</p>
|
||||||
<p class="mb-1"><i class="bi bi-house text-success me-2"></i><strong>Address:</strong> </p>
|
<p class="mb-1"><i class="bi bi-house text-success me-2"></i><strong>Address:</strong> </p>
|
||||||
<p class="mb-1"><i class="bi bi-person text-success me-2"></i><strong>Coordinator:</strong> {{ event.coordinator_name }}</p>
|
<p class="mb-1"><i class="bi bi-person text-success me-2"></i><strong>Coordinator:</strong> {{ event.coordinator_name }}</p>
|
||||||
@@ -159,7 +161,9 @@
|
|||||||
<div class="col-md-8">
|
<div class="col-md-8">
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<p class="mb-1"><i class="bi bi-calendar-event text-secondary me-2"></i><strong>Date:</strong> {{ event.start_date }}</p>
|
<p class="mb-1"><i class="bi bi-calendar-event text-secondary me-2"></i><strong>Date:</strong> {{ event.start_date }}</p>
|
||||||
<p class="mb-1"><i class="bi bi-clock text-secondary me-2"></i><strong>Time:</strong> 9:00 AM - 12:00 PM</p>
|
{% if event.time_range_display %}
|
||||||
|
<p class="mb-1"><i class="bi bi-clock text-secondary me-2"></i><strong>Time:</strong> {{ event.time_range_display }}</p>
|
||||||
|
{% endif %}
|
||||||
<p class="mb-1"><i class="bi bi-geo-alt text-secondary me-2"></i><strong>Location:</strong> {{ event.location_name }}</p>
|
<p class="mb-1"><i class="bi bi-geo-alt text-secondary me-2"></i><strong>Location:</strong> {{ event.location_name }}</p>
|
||||||
<p class="mb-1"><i class="bi bi-house text-secondary me-2"></i><strong>Address:</strong> </p>
|
<p class="mb-1"><i class="bi bi-house text-secondary me-2"></i><strong>Address:</strong> </p>
|
||||||
<p class="mb-1"><i class="bi bi-person text-secondary me-2"></i><strong>Coordinator:</strong> {{ event.coordinator_name }}</p>
|
<p class="mb-1"><i class="bi bi-person text-secondary me-2"></i><strong>Coordinator:</strong> {{ event.coordinator_name }}</p>
|
||||||
|
|||||||
@@ -321,6 +321,23 @@ class CalendarEventTests(TestCase):
|
|||||||
self.assertFalse(undated.past_event())
|
self.assertFalse(undated.past_event())
|
||||||
self.assertFalse(undated.future_event())
|
self.assertFalse(undated.future_event())
|
||||||
|
|
||||||
|
def test_time_range_display(self):
|
||||||
|
event = CalendarEvent.objects.create(
|
||||||
|
event_name="Timed Event",
|
||||||
|
start_time=datetime.time(11, 0),
|
||||||
|
end_time=datetime.time(15, 0),
|
||||||
|
)
|
||||||
|
self.assertEqual(event.time_range_display(), "11:00 AM - 3:00 PM")
|
||||||
|
|
||||||
|
start_only = CalendarEvent.objects.create(
|
||||||
|
event_name="Start Only",
|
||||||
|
start_time=datetime.time(9, 30),
|
||||||
|
)
|
||||||
|
self.assertEqual(start_only.time_range_display(), "9:30 AM")
|
||||||
|
|
||||||
|
no_time = CalendarEvent.objects.create(event_name="No Time")
|
||||||
|
self.assertEqual(no_time.time_range_display(), "")
|
||||||
|
|
||||||
def test_calendar_page_splits_past_and_future(self):
|
def test_calendar_page_splits_past_and_future(self):
|
||||||
today = datetime.date.today()
|
today = datetime.date.today()
|
||||||
CalendarEvent.objects.create(
|
CalendarEvent.objects.create(
|
||||||
|
|||||||
Reference in New Issue
Block a user