membersystem/src/membership/models.py

77 lines
2.2 KiB
Python

from typing import Optional
from django.contrib.postgres.fields import DateTimeRangeField
from django.db import models
from django.utils import timezone
from django.utils.translation import gettext as _
class CreatedModifiedAbstract(models.Model):
modified = models.DateTimeField(auto_now=True, verbose_name=_("modified"))
created = models.DateTimeField(auto_now_add=True, verbose_name=_("created"))
class Meta:
abstract = True
class Membership(CreatedModifiedAbstract):
"""
Tracks that a user has membership of a given type for a given period.
"""
class QuerySet(models.QuerySet):
def for_user(self, user):
return self.filter(user=user)
def _current(self):
return self.filter(period__contains=timezone.now())
def current(self) -> Optional["Membership"]:
try:
return self._current().get()
except self.model.DoesNotExist:
return None
def previous(self):
# A naïve way to get previous by just excluding the current. This
# means that there must be some protection against "future"
# memberships.
return self.all().difference(self._current())
objects = QuerySet.as_manager()
class Meta:
verbose_name = _("membership")
verbose_name_plural = _("memberships")
user = models.ForeignKey("auth.User", on_delete=models.PROTECT)
membership_type = models.ForeignKey(
"membership.MembershipType",
related_name="memberships",
verbose_name=_("subscription type"),
on_delete=models.PROTECT,
)
period = DateTimeRangeField(help_text=_("The duration this subscription is for. "))
def __str__(self):
return f"{self.user} - {self.period}"
class MembershipType(CreatedModifiedAbstract):
"""
Models membership types. Currently only a name, but will in the future
possibly contain more information like fees.
"""
class Meta:
verbose_name = _("membership type")
verbose_name_plural = _("membership types")
name = models.CharField(verbose_name=_("name"), max_length=64)
def __str__(self):
return self.name