pulseapi/profiles/models/categories.py (87 lines of code) (raw):
from django.db import models
from django.core.exceptions import ValidationError
from django.utils.translation import gettext_lazy as _
from pulseapi.utility.validators import YearValidator
class ProfileType(models.Model):
"""
See https://github.com/mozilla/network-pulse/issues/657
Values that should exist (handled via migration):
- plain
- staff
- fellow
- board member
- grantee
"""
value = models.CharField(
max_length=50,
unique=True
)
def get_default_profile_type():
(default, _) = ProfileType.objects.get_or_create(value='plain')
return default
def __str__(self):
return self.value
class ProgramType(models.Model):
"""
See https://github.com/mozilla/network-pulse/issues/657
These values are determined by pulse API administrators
(tech policy fellowship, mozfest speaker, etc)
"""
value = models.CharField(
max_length=150,
unique=True
)
def __str__(self):
return self.value
class ProgramYear(models.Model):
"""
See https://github.com/mozilla/network-pulse/issues/657
You'd think this would be 4 characters, but a "year" is
not a calendar year, so the year could just as easily
be "summer 2017" or "Q2 2016 - Q1 2018", so this is the
same kind of simple value model that the profile and
program types use.
"""
value = models.CharField(
max_length=25,
unique=True
)
def __str__(self):
return self.value
class CohortRecord(models.Model):
profile = models.ForeignKey(
'profiles.UserProfile',
on_delete=models.CASCADE,
related_name='cohort_records',
)
program = models.ForeignKey(
'profiles.ProgramType',
on_delete=models.PROTECT,
related_name='profile_cohort_records',
)
year = models.PositiveSmallIntegerField(
# TODO: Change to MaxValueValidator with callable when
# we update to Django > v2.2
validators=[YearValidator(max_offset=2)],
null=True,
blank=True,
)
cohort_name = models.CharField(
null=True,
blank=True,
max_length=200,
)
def __str__(self):
return f'{self.profile.name} - {self.program} {str(self.year)} {self.cohort_name}'
def clean(self):
super().clean()
# Don't allow both the cohort and year to be empty
if self.year is None and not self.cohort_name:
raise ValidationError(
_('Either the year or cohort must have a value')
)
def save(self, *args, **kwargs):
self.full_clean()
super().save(*args, **kwargs)
class Meta:
verbose_name = 'cohort record'
# This meta option creates an _order column in the table
# See https://docs.djangoproject.com/en/1.11/ref/models/options/#order-with-respect-to for more details
order_with_respect_to = 'profile'
# We prefix the index name in the database with uk to indicate that the constraint is a unique key
indexes = [
models.Index(fields=['profile', '_order'], name='uk_membership_profile_order'),
]
class ProfileRole(models.Model):
profile = models.ForeignKey(
'profiles.UserProfile',
on_delete=models.CASCADE,
related_name='related_types',
)
profile_type = models.ForeignKey(
'profiles.ProfileType',
on_delete=models.CASCADE,
related_name='related_profiles',
)
is_current = models.BooleanField(default=True)
def __str__(self):
copular_verb = 'is' if self.is_current else 'was'
return f'{self.profile.name} {copular_verb} a {self.role}'
class Meta:
# This meta option creates an _order column in the table
# See https://docs.djangoproject.com/en/1.11/ref/models/options/#order-with-respect-to for more details
order_with_respect_to = 'profile'
# We prefix the index name in the database with uk to indicate that the constraint is a unique key
indexes = [
models.Index(fields=['profile', 'is_current', '_order'], name='uk_role_profile_current_order'),
models.Index(fields=['profile', 'is_current', 'profile_type'], name='uk_role_profile_current_type'),
]