Beispiel #1
0
class Booking(models.Model):

    room = models.ForeignKey(Room,
                             on_delete=models.CASCADE,
                             related_name='bookings')
    guest = models.ForeignKey(User,
                              related_name='bookings',
                              on_delete=models.CASCADE)
    duration = DateTimeRangeField(db_index=True)
    price = models.DecimalField(max_digits=100,
                                decimal_places=2,
                                blank=True,
                                null=True)  #t
    total = models.DecimalField(max_digits=100,
                                decimal_places=2,
                                blank=True,
                                null=True)  #t
    status = models.CharField(max_length=120,
                              default='created',
                              choices=BOOKING_STATUS_CHOICES)
    active = models.BooleanField(default=True)
    create_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    def __str__(self):
        return "{} booking for {}".format(self.guest.first_name,
                                          self.room.name)
Beispiel #2
0
class Election(models.Model):
    """
    An election, which keeps track of the options to vote for, and who has voted within it.
    """
    title = models.CharField(max_length=255, default="")
    description = MarkdownxField(default="")
    created = models.DateTimeField(auto_now_add=True)
    voters = models.ManyToManyField(User, blank=True)
    open_time = DateTimeRangeField()
    aber_only = models.BooleanField(default=False)

    def get_absolute_url(self):
        return reverse("voting:election_details",
                       kwargs={"election_id": self.id})

    def __str__(self):
        return self.title

    def is_open(self):
        """
        Is this election currently open (as in, can users vote in it right now)
        """
        return pytz.utc.localize(datetime.datetime.now()) in self.open_time

    def can_vote(self, user):
        """
        Check that the election is currently open and that the user has not already voted
        :param user: The user to check has voted
        :return: True if the user can vote
        """
        return self.is_open() \
            and user not in self.voters \
            and user.is_aber_student() if self.aber_only else True
Beispiel #3
0
class NursingSchedule(models.Model):
    class Meta:
        db_table = "patient_nursing_schedule"

    objects = ScheduleManager()

    patient = models.ForeignKey(Profile, related_name='nursing_schedule', on_delete=models.CASCADE)
    employee = models.ForeignKey("employee.Profile", related_name='nursing_schedule', on_delete=models.CASCADE)
    schedule = DateTimeRangeField()
    flow_control = models.DateTimeField(null=True)

    def today_courses(self):
        return self.patient.course_schedule.extra(
            where=("(weekly_mask & (1 << EXTRACT(DOW FROM current_timestamp AT TIME ZONE 'Asia/Taipei')::int)) > 0", ))

    def fetch_next_question(self):
        courses_id = self.patient.course_schedule.extra(
            where=("(weekly_mask & (1 << EXTRACT(DOW FROM current_timestamp AT TIME ZONE 'Asia/Taipei')::int)) > 0", )
        ).values_list('table_id', flat=True)
        items = CourseQuestion.objects.filter(table_id__in=courses_id).extra(
            where=("care_course_question.scheduled_at > (SELECT (flow_control AT TIME ZONE 'Asia/Taipei')::Time FROM patient_nursing_schedule WHERE id = %i)" % self.id,
                   "care_course_question.scheduled_at <= (SELECT (UPPER(schedule) AT TIME ZONE 'Asia/Taipei')::Time FROM patient_nursing_schedule WHERE id = %i)" % self.id)
        ).select_related("question").order_by('scheduled_at')
        t = None
        for it in items:
            if not t:
                yield it
                t = it.scheduled_at
            elif it.scheduled_at == t:
                yield it
            else:
                return

    def __str__(self):
        return "%s#班表 %s/%s@%s" % (self.id, self.patient, self.employee, self.schedule.lower)
Beispiel #4
0
class Booking(models.Model):
    """ bookings model """
    guest = models.ForeignKey(CustomUser,
                              on_delete=models.CASCADE,
                              related_name='guest')
    num_guests = models.IntegerField(default=2, null=False)
    listing = models.ForeignKey(Listing, on_delete=models.CASCADE)
    price_type = models.CharField(max_length=20,
                                  choices=PRICE_TYPE,
                                  null=False,
                                  default="daily")
    total_price = models.IntegerField(validators=[MinValueValidator(0)])
    date_time_range = DateTimeRangeField(null=True)
    duration = models.DurationField(default=timedelta(days=1))
    confirmed = models.BooleanField(null=False, default=False)

    @classmethod
    def calculate_duration(cls, date_time_range):
        """ calculate end_time - start_time """

        return date_time_range.upper - date_time_range.lower

    @classmethod
    def calculate_total_price(cls, duration, price_type, listing):
        """ Calculate price * duration """

        if price_type == 'hourly':
            return duration.hours * listing.price_per_hour
        if price_type == 'daily':
            return duration.days * listing.price_per_day
        if price_type == 'monthly':
            return duration.months * listing.price_per_month

    def __str__(self):
        return f"Booking {self.id}"
Beispiel #5
0
class drs(models.Model):
    period = DateTimeRangeField()
    account = models.ForeignKey(Account, on_delete=models.CASCADE)
    cb = models.DecimalField(max_digits=14, decimal_places=3)

    def __str__(self):
        return f"{self.period} {self.account.name} {self.cb} "
Beispiel #6
0
class Listener(models.Model):
    ip_address = models.GenericIPAddressField(verbose_name='IP address')
    stream = models.ForeignKey(Stream, on_delete=models.PROTECT)
    session = DateTimeRangeField()
    duration = models.DurationField()
    referer = models.CharField(max_length=255)
    user_agent = models.ForeignKey(UserAgent,
                                   on_delete=models.SET_NULL,
                                   null=True)
    country = CountryField(null=True)
    city = models.CharField(max_length=255, null=True)
    latitude = models.DecimalField(max_digits=9, decimal_places=6, null=True)
    longitude = models.DecimalField(max_digits=9, decimal_places=6, null=True)

    class Meta:
        unique_together = ('ip_address', 'stream', 'session', 'user_agent')
        ordering = ('-session', )
        indexes = [
            GistIndex(fields=[
                'session',
            ]),
        ]

    @property
    def connected_at(self):
        return self.session.lower

    @property
    def disconnected_at(self):
        return self.session.upper

    def __str__(self):
        return self.ip_address
class AppointmentSchedule(models.Model):
    """
    Model represent schedule for booked appointment.
    The end of appointment will automatic calculated from treatments duration
    """
    class Meta:
        db_table = 'appointment_schedules'

    appointment = models.OneToOneField(Appointment, related_name='schedule')
    doctor = models.ForeignKey(settings.AUTH_USER_MODEL,
                               related_name='appointment_schedules')
    duration = DateTimeRangeField(null=True)

    def __str__(self):
        return "Appointment {} for doctor {} at {}".format(
            self.appointment_id, self.doctor, self.duration)

    @staticmethod
    def create_from(appointment: Appointment):
        appointment = Appointment.objects.get(pk=appointment.pk)
        treatments_duration = sum(
            [getattr(t, 'duration', 0) for t in appointment.treatments.all()])
        start_time = appointment.date_time
        end_time = start_time + timedelta(minutes=treatments_duration)
        try:
            appointment_schedule = AppointmentSchedule.objects.get(
                appointment=appointment)
        except AppointmentSchedule.DoesNotExist:
            appointment_schedule = AppointmentSchedule(appointment=appointment)

        appointment_schedule.doctor = appointment.doctor
        appointment_schedule.duration = DateTimeTZRange(start_time, end_time)
        appointment_schedule.save()
        return appointment_schedule
Beispiel #8
0
class Product(CreatedUpdatedModel, UUIDModel):
    class Meta:
        verbose_name = 'Product'
        verbose_name_plural = 'Products'
        ordering = ['available_in', 'price']

    category = models.ForeignKey('shop.ProductCategory',
                                 related_name='products')

    name = models.CharField(max_length=150)
    slug = models.SlugField()

    price = models.IntegerField(
        help_text=_('Price of the product (in DKK, including VAT).'))

    description = models.TextField()

    available_in = DateTimeRangeField(help_text=_(
        'Which period is this product available for purchase? | '
        '(Format: YYYY-MM-DD HH:MM) | Only one of start/end is required'))

    objects = ProductQuerySet.as_manager()

    def __str__(self):
        return '{} ({} DKK)'.format(
            self.name,
            self.price,
        )

    def is_available(self):
        now = timezone.now()
        return now in self.available_in
Beispiel #9
0
class ResourceDailyOpeningHours(models.Model):
    """
    Calculated automatically for each day the resource is open
    """
    resource = models.ForeignKey(Resource,
                                 related_name='opening_hours',
                                 on_delete=models.CASCADE,
                                 db_index=True)
    open_between = DateTimeRangeField()

    def clean(self):
        super().clean()
        if self.objects.filter(resource=self.resource,
                               open_between__overlaps=self.open_between):
            raise ValidationError(_("Overlapping opening hours"))

    class Meta:
        unique_together = [('resource', 'open_between')]
        indexes = [GistIndex(fields=['open_between'])]

    def __str__(self):
        if isinstance(self.open_between, tuple):
            lower = self.open_between[0]
            upper = self.open_between[1]
        else:
            lower = self.open_between.lower
            upper = self.open_between.upper
        return "%s: %s -> %s" % (self.resource, lower, upper)
Beispiel #10
0
class TeamShift(CampRelatedModel):
    class Meta:
        ordering = ("shift_range", )

    team = models.ForeignKey(
        'teams.Team',
        related_name='shifts',
        on_delete=models.PROTECT,
        help_text='The team this shift belongs to',
    )

    shift_range = DateTimeRangeField()

    team_members = models.ManyToManyField(
        TeamMember,
        blank=True,
    )

    people_required = models.IntegerField(default=1)

    @property
    def camp(self):
        """ All CampRelatedModels must have a camp FK or a camp property """
        return self.team.camp

    camp_filter = 'team__camp'

    def __str__(self):
        return "{} team shift from {} to {}".format(self.team.name,
                                                    self.shift_range.lower,
                                                    self.shift_range.upper)

    @property
    def users(self):
        return [member.user for member in self.team_members.all()]
Beispiel #11
0
class PostgresModel(Model):
    int_array = ArrayField(IntegerField(null=True, blank=True),
                           size=3,
                           null=True,
                           blank=True)

    hstore = HStoreField(null=True, blank=True)
    try:
        from django.contrib.postgres.fields import JSONField
        json = JSONField(null=True, blank=True)
    except ImportError:
        pass

    int_range = IntegerRangeField(null=True, blank=True)
    try:
        from django.contrib.postgres.fields import FloatRangeField
        float_range = FloatRangeField(null=True, blank=True)
    except ImportError:
        pass

    try:
        from django.contrib.postgres.fields import DecimalRangeField
        decimal_range = DecimalRangeField(null=True, blank=True)
    except ImportError:
        pass
    date_range = DateRangeField(null=True, blank=True)
    datetime_range = DateTimeRangeField(null=True, blank=True)

    class Meta:
        # Tests schema name in table name.
        db_table = '"public"."cachalot_postgresmodel"'
Beispiel #12
0
class SubscriptionPeriodItem(StarterModel):
    subscription = models.ForeignKey(Subscription,
                                     on_delete=models.CASCADE,
                                     related_name='subscription_period_items')
    date_range = DateTimeRangeField()
    payment_status = EnumChoiceField(PaymentStatus,
                                     default=PaymentStatus.PENDING,
                                     max_length=32)
Beispiel #13
0
class PostgreFieldsModel(models.Model):
    date_range_field = DateRangeField()
    datetime_range_field = DateTimeRangeField()
    integer_range_field = IntegerRangeField()
    decimal_range_field = DecimalRangeField()

    class Meta:
        app_label = 'tests'
Beispiel #14
0
class FieldHistory(models.Model):
    """Model for a column/field history table"""
    entity = None  # type: models.ForeignKey
    effective = DateTimeRangeField()
    vclock = IntegerRangeField()

    class Meta:
        abstract = True
Beispiel #15
0
class Ad(BaseModel):
    """
    Ads model.
    """
    class Type:
        dating = 'DATING'
        meeting = 'MEETING'
        travel = 'TRAVEL'
        choices = (
            (dating, _('Dating')),
            (meeting, _('Meeting')),
            (travel, _('Travel')),
        )

    user = models.ForeignKey(get_user_model(),
                             related_name='ads',
                             on_delete=models.CASCADE,
                             help_text=_('Ad creator.'))
    type = models.CharField(max_length=16,
                            choices=Type.choices,
                            help_text=_('Ad type.'))
    address = models.CharField(max_length=256, help_text=_('Ad address.'))
    point = models.PointField(
        help_text=_('Geolocation point (in GeoJSON format).'))
    sex = models.CharField(max_length=1,
                           choices=get_user_model().Sex.choices,
                           default=get_user_model().Sex.none,
                           help_text=_('Valid values: M, F, N'))
    ages = IntegerRangeField(help_text=_('Ad age range'))
    title = models.CharField(max_length=128, help_text=_('Title'))
    text = models.TextField(help_text=_('Ad description'))
    period = DateTimeRangeField(default=default_period,
                                help_text=_('Ad period'))
    favorited_for = ArrayField(
        models.CharField(max_length=36),
        help_text=_("Favorite for this users (list of UUIDs)."),
        default=list)
    viewed_by = ArrayField(models.CharField(max_length=36),
                           help_text=_("View by this users (list of UUIDs)."),
                           default=list)
    is_active = models.BooleanField(default=False,
                                    help_text=_('As is publicly published.'))
    is_blocked = models.BooleanField(default=False,
                                     help_text=_('Is blocked by moderator'))

    objects = AdManager()

    class Meta:
        db_table = 'ads'
        ordering = ('-created_at', )

    @cached_property
    def owner(self):
        return self.user

    @property
    def short_text(self):
        return truncatewords(self.text, 6)
Beispiel #16
0
class Datastream(models.Model):
    """
    Datatsream model type definition. Related fields are defined it related models.
    """
    name = models.TextField("Name")
    description = models.TextField("Description")
    unitOfMeasurement = JSONField(verbose_name="Unit of Measurement")
    observationType = models.TextField(
        verbose_name="Observation Type",
        choices=OBSERVATION_TYPES,
        default=
        "http://www.opengis.net/def/observationType/OGC-OM/2.0/OM_Observation")
    observedArea = models.PolygonField(blank=True,
                                       null=True,
                                       verbose_name="Observed Area")
    phenomenonTime = DateTimeRangeField(
        blank=True,
        null=True,
        # validators=[Validators.validate_interval],
        verbose_name="Phenomenon Time")
    resultTime = DateTimeRangeField(
        blank=True,
        null=True,
        # validators=[Validators.validate_interval],
        verbose_name="Result Time")
    Thing = models.ForeignKey(Thing,
                              on_delete=models.CASCADE,
                              related_name="Datastream",
                              verbose_name='Thing')
    Sensor = models.ForeignKey("Sensor",
                               on_delete=models.CASCADE,
                               related_name="Datastream",
                               verbose_name="Sensor")
    ObservedProperty = models.ForeignKey("ObservedProperty",
                                         on_delete=models.CASCADE,
                                         related_name="Datastream",
                                         verbose_name="Observed Property")

    class Meta:
        verbose_name = "Datastream"
        verbose_name_plural = "Datastreams"

    def __str__(self):
        return self.name
Beispiel #17
0
class Subscriptions(models.Model):
    account = models.ForeignKey(Account, on_delete=models.PROTECT)
    plan = models.CharField(max_length=30, blank=False)
    period = DateTimeRangeField(null=True, blank=True)

    def __str__(self):
        return f'{self.account} {self.plan} {self.period}'

    class Meta:
        verbose_name_plural = 'Subscriptions'
Beispiel #18
0
class StopSuspension(models.Model):
    dates = DateTimeRangeField(null=True, blank=True)
    text = models.TextField(blank=True)
    stops = models.ManyToManyField('busstops.StopPoint')
    service = models.ForeignKey('busstops.Service',
                                models.CASCADE,
                                null=True,
                                blank=True)

    def __str__(self):
        return self.text or str(self.dates)
Beispiel #19
0
class Experiment(Model):
    __slots__ = ['experiment_id', 'name', 'qgroup', 'consent_file', 'priority', 'time_range', 'description']
    experiment_id = AutoField(primary_key=True)
    name = CharField(max_length=64)
    qgroup = ForeignKey(QGroup)
    consent_file = CharField(max_length=64)
    priority = PositiveSmallIntegerField(default=0)
    time_range = DateTimeRangeField()
    description = TextField(default=None)

    def __unicode__(self):
        return '%s [%s] - [%s]' % (self.experiment_id, self.name, self.qgroup.qgroup_id)
Beispiel #20
0
    class PostgresModel(Model):
        int_array = ArrayField(IntegerField(null=True, blank=True),
                               size=3,
                               null=True,
                               blank=True)

        hstore = HStoreField(null=True, blank=True)

        int_range = IntegerRangeField(null=True, blank=True)
        float_range = FloatRangeField(null=True, blank=True)
        date_range = DateRangeField(null=True, blank=True)
        datetime_range = DateTimeRangeField(null=True, blank=True)
Beispiel #21
0
class UserProfession(models.Model):
    user = models.ForeignKey(User,
                             related_name="professions",
                             on_delete=models.CASCADE,
                             db_index=True)
    profession = models.ForeignKey(Profession,
                                   blank=True,
                                   null=True,
                                   on_delete=models.CASCADE)
    period = DateTimeRangeField()

    objects = UserProfessionQuerySet.as_manager()
Beispiel #22
0
class Channel(models.Model):
    name = models.CharField(max_length=254, verbose_name='Ex. FR.CHMF.00.BHZ')
    span = DateTimeRangeField(
        verbose_name='Date time range (start/end)',
        help_text='If no end date for the moment, just add start date')
    states = models.ManyToManyField('gissmo.State')

    def __str__(self):
        return '%s' % self.name

    def __unicode__(self):
        return '%s' % self.name
Beispiel #23
0
class TeamTask(CampRelatedModel):
    team = models.ForeignKey(
        "teams.Team",
        related_name="tasks",
        on_delete=models.PROTECT,
        help_text="The team this task belongs to",
    )
    name = models.CharField(max_length=100,
                            help_text="Short name of this task")
    slug = models.SlugField(max_length=255,
                            blank=True,
                            help_text="url slug, leave blank to autogenerate")
    description = models.TextField(
        help_text="Description of the task. Markdown is supported.")
    when = DateTimeRangeField(
        blank=True,
        null=True,
        help_text="When does this task need to be started and/or finished?",
    )
    completed = models.BooleanField(
        help_text="Check to mark this task as completed.", default=False)

    class Meta:
        ordering = ["completed", "when", "name"]
        unique_together = (("name", "team"), ("slug", "team"))

    def get_absolute_url(self):
        return reverse_lazy(
            "teams:task_detail",
            kwargs={
                "camp_slug": self.team.camp.slug,
                "team_slug": self.team.slug,
                "slug": self.slug,
            },
        )

    @property
    def camp(self):
        """ All CampRelatedModels must have a camp FK or a camp property """
        return self.team.camp

    camp_filter = "team__camp"

    def save(self, **kwargs):
        # generate slug if needed
        if not self.slug:
            self.slug = unique_slugify(
                self.name,
                slugs_in_use=self.__class__.objects.filter(
                    team=self.team).values_list("slug", flat=True),
            )
        super().save(**kwargs)
class Statistics(models.Model):
    name = models.CharField(max_length=256)
    active = DateTimeRangeField(null=True, blank=True)
    terminals = models.ManyToManyField("Terminal")

    class Meta:
        ordering = ("id", )
        permissions = ((("view_statistics",
                         _("View Statistics")), ) if django.VERSION <
                       (2, 1) else tuple())

    def __str__(s):
        return f"{s.name} ({s.terminals.count()} Terminals / {s.active})"
Beispiel #25
0
class Product(CreatedUpdatedModel, UUIDModel):
    class Meta:
        verbose_name = 'Product'
        verbose_name_plural = 'Products'
        ordering = ['available_in', 'price', 'name']

    category = models.ForeignKey('shop.ProductCategory',
                                 related_name='products')

    name = models.CharField(max_length=150)
    slug = models.SlugField(unique=True, max_length=100)

    price = models.IntegerField(
        help_text=_('Price of the product (in DKK, including VAT).'))

    description = models.TextField()

    available_in = DateTimeRangeField(help_text=_(
        'Which period is this product available for purchase? | '
        '(Format: YYYY-MM-DD HH:MM) | Only one of start/end is required'))

    ticket_type = models.ForeignKey('tickets.TicketType',
                                    null=True,
                                    blank=True)

    objects = ProductQuerySet.as_manager()

    def __str__(self):
        return '{} ({} DKK)'.format(
            self.name,
            self.price,
        )

    def clean(self):
        if self.category.name == 'Tickets' and not self.ticket_type:
            raise ValidationError(
                'Products with category Tickets need a ticket_type')

    def is_available(self):
        now = timezone.now()
        return now in self.available_in

    def is_old(self):
        now = timezone.now()
        if hasattr(self.available_in, 'upper') and self.available_in.upper:
            return self.available_in.upper < now
        return False

    def is_upcoming(self):
        now = timezone.now()
        return self.available_in.lower > now
Beispiel #26
0
class Match(models.Model):
    created_time = models.DateTimeField(_('created time'), auto_now_add=True)
    updated_time = models.DateTimeField(_('updated time'), auto_now=True)
    is_enable = models.BooleanField(_('is enable'), default=True)
    title = models.CharField(_('title'), max_length=80)
    execute_time_range = DateTimeRangeField(_('execute time range'))
    stadium = models.ForeignKey('Stadium', verbose_name=_('stadium'), on_delete=models.CASCADE, related_name='matches')

    class Meta:
        verbose_name = _("Match")
        verbose_name_plural = _("Matches")

    def __str__(self):
        return self.title
Beispiel #27
0
class FacilityOpeningHours(
        ExportModelOperationsMixin("facility_opening_hours"),
        CampRelatedModel,
):
    """
    This model contains opening hours for facilities which are not always open.
    If a facility has zero entries in this model it means is always open.
    If a facility has one or more periods of opening hours defined in this model
    it is considered closed outside of the period(s) defined in this model.
    """
    class Meta:
        ordering = ["when"]
        constraints = [
            # we do not want overlapping hours for the same Facility
            ExclusionConstraint(
                name="prevent_facility_opening_hours_overlaps",
                expressions=[
                    ("when", RangeOperators.OVERLAPS),
                    ("facility", RangeOperators.EQUAL),
                ],
            ),
        ]

    facility = models.ForeignKey(
        "facilities.Facility",
        related_name="opening_hours",
        on_delete=models.PROTECT,
        help_text="The Facility to which these opening hours belong.",
    )

    when = DateTimeRangeField(
        db_index=True,
        help_text="The period when this facility is open.",
    )

    notes = models.TextField(
        blank=True,
        help_text=
        "Any notes for this period like 'no hot food after 20' or 'no alcohol sale after 02'. Optional.",
    )

    @property
    def camp(self):
        return self.facility.camp

    camp_filter = "facility__facility_type__responsible_team__camp"

    @property
    def duration(self):
        return self.when.upper - self.when.lower
Beispiel #28
0
class State(models.Model):
    equipment = models.ForeignKey('gissmo.Equipment',
                                  related_name='states',
                                  on_delete=models.DO_NOTHING)
    span = DateTimeRangeField(
        verbose_name='Date time range (start/end)',
        help_text='If no end date for the moment, just add start date')
    data = JSONField()

    def __str__(self):
        return '%s - %s' % (self.equipment.name, self.span)

    def __unicode__(self):
        return '%s - %s' % (self.equipment.name, self.span)
Beispiel #29
0
class Ticket(GenericDatetimeModel):
    mentor = models.ForeignKey(Mentor,
                               verbose_name='멘토',
                               null=True,
                               on_delete=models.SET_NULL)

    sale_period = DateTimeRangeField('판매 기간')

    is_active = models.BooleanField('활성화 여부', default=False)

    class Meta:
        db_table = 'tickets'
        verbose_name = '티켓'
        verbose_name_plural = '티켓들'
Beispiel #30
0
class TeamTask(CampRelatedModel):
    team = models.ForeignKey(
        'teams.Team',
        related_name='tasks',
        on_delete=models.PROTECT,
        help_text='The team this task belongs to',
    )
    name = models.CharField(
        max_length=100,
        help_text='Short name of this task',
    )
    slug = models.SlugField(
        max_length=255,
        blank=True,
        help_text='url slug, leave blank to autogenerate',
    )
    description = models.TextField(
        help_text='Description of the task. Markdown is supported.')
    when = DateTimeRangeField(
        blank=True,
        null=True,
        help_text='When does this task need to be started and/or finished?')
    completed = models.BooleanField(
        help_text='Check to mark this task as completed.', default=False)

    class Meta:
        ordering = ['completed', 'when', 'name']
        unique_together = (('name', 'team'), ('slug', 'team'))

    def get_absolute_url(self):
        return reverse_lazy('teams:task_detail',
                            kwargs={
                                'camp_slug': self.team.camp.slug,
                                'team_slug': self.team.slug,
                                'slug': self.slug
                            })

    @property
    def camp(self):
        """ All CampRelatedModels must have a camp FK or a camp property """
        return self.team.camp

    camp_filter = 'team__camp'

    def save(self, **kwargs):
        # generate slug if needed
        if not self.slug:
            self.slug = slugify(self.name)
        super().save(**kwargs)