39586-vm/core/models.py
2026-04-12 12:41:59 +00:00

89 lines
3.1 KiB
Python

from django.db import models
from django.template.defaultfilters import slugify
from django.urls import reverse
from django.utils import timezone
class Event(models.Model):
title = models.CharField(max_length=180)
slug = models.SlugField(unique=True, max_length=200, blank=True)
summary = models.CharField(max_length=260)
description = models.TextField()
venue = models.CharField(max_length=180)
start_at = models.DateTimeField()
end_at = models.DateTimeField()
capacity = models.PositiveIntegerField(blank=True, null=True)
is_published = models.BooleanField(default=True)
registration_opens = models.DateTimeField(blank=True, null=True)
registration_closes = models.DateTimeField(blank=True, null=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
ordering = ['start_at']
def __str__(self):
return self.title
def save(self, *args, **kwargs):
if not self.slug:
base_slug = slugify(self.title)[:180] or 'event'
slug = base_slug
counter = 2
while Event.objects.exclude(pk=self.pk).filter(slug=slug).exists():
slug = f'{base_slug}-{counter}'[:200]
counter += 1
self.slug = slug
super().save(*args, **kwargs)
def get_absolute_url(self):
return reverse('event_detail', args=[self.slug])
@property
def confirmed_registrations_count(self):
return self.registrations.filter(status=Registration.Status.CONFIRMED).count()
@property
def waitlist_count(self):
return self.registrations.filter(status=Registration.Status.WAITLIST).count()
@property
def spots_remaining(self):
if self.capacity is None:
return None
return max(self.capacity - self.confirmed_registrations_count, 0)
@property
def registration_is_open(self):
now = timezone.now()
if not self.is_published:
return False
if self.registration_opens and now < self.registration_opens:
return False
if self.registration_closes and now > self.registration_closes:
return False
return True
class Registration(models.Model):
class Status(models.TextChoices):
CONFIRMED = 'confirmed', 'Confirmed'
WAITLIST = 'waitlist', 'Waitlist'
event = models.ForeignKey(Event, on_delete=models.CASCADE, related_name='registrations')
full_name = models.CharField(max_length=160)
email = models.EmailField()
company = models.CharField(max_length=160, blank=True)
notes = models.TextField(blank=True)
status = models.CharField(max_length=24, choices=Status.choices, default=Status.CONFIRMED)
created_at = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ['created_at']
constraints = [
models.UniqueConstraint(fields=['event', 'email'], name='unique_registration_per_event_email'),
]
def __str__(self):
return f'{self.full_name} · {self.event.title}'