2015-10-20 17:13:07 +02:00

250 行
7.1 KiB
Python
Raw Blame 履歴

このファイルには曖昧(ambiguous)なUnicode文字が含まれています

このファイルには、他の文字と見間違える可能性があるUnicode文字が含まれています。 それが意図的なものと考えられる場合は、この警告を無視して構いません。 それらの文字を表示するにはエスケープボタンを使用します。

# -*- coding: utf-8 -*-
"""
Models for the Duck Booking Tool
"""
from django.conf import settings
from django.contrib.auth.models import User
from django.db import models
from django.utils import timezone
from django.utils.encoding import python_2_unicode_compatible
from fuzzywuzzy import fuzz
from .ducklevel import minutes_to_level
@python_2_unicode_compatible
class Species(models.Model):
"""
Model to hold the Ducks species
"""
name = models.CharField(max_length=40, unique=True)
def __str__(self):
return self.name
@python_2_unicode_compatible
class Location(models.Model):
"""
Model to hold the possible locations of the Ducks
"""
name = models.CharField(max_length=50)
def __str__(self):
return self.name
@python_2_unicode_compatible
class Competence(models.Model):
"""
Model to hold Duck competences
"""
name = models.CharField(max_length=255, unique=True)
added_at = models.DateTimeField(default=timezone.now)
added_by = models.ForeignKey(User)
def __str__(self):
return self.name
@classmethod
def get_similar_comps(cls, name):
"""
Get competence names similar to name
"""
comps = cls.objects.values_list('name', flat=True)
ret = ()
for competence in comps:
similarity = fuzz.ratio(name.lower(), competence.lower())
# This ratio is subject to change
if similarity > settings.MIN_FUZZY_SIMILARITY:
ret = ret + (competence,)
return ret
@python_2_unicode_compatible
class Duck(models.Model):
"""
Model to hold Duck data
"""
name = models.CharField(max_length=80, null=True, blank=True)
color = models.CharField(max_length=6)
species = models.ForeignKey(Species)
location = models.ForeignKey(Location)
comps = models.ManyToManyField(Competence, through='DuckCompetence')
donated_by = models.ForeignKey(User)
donated_at = models.DateTimeField(default=timezone.now)
adopted_by = models.ForeignKey(User, related_name='adopted_ducks', null=True, blank=True)
adopted_at = models.DateTimeField(null=True, blank=True)
bookings = models.ManyToManyField(User, through='Booking', related_name='+')
on_holiday_since = models.DateTimeField(null=True, blank=True)
on_holiday_until = models.DateTimeField(null=True, blank=True)
def __str__(self):
if self.name == None or self.name == '':
return 'Unnamed :('
return self.name
def age(self):
"""
Get the age of the duck (time since the duck has been registered
in the tool)
"""
seconds_d = timezone.now() - self.donated_at
seconds = seconds_d.total_seconds()
if seconds < 0:
return -1
return seconds
def dpx(self):
"""
Get the Duck Popularity indeX for this duck
"""
all_time = Booking.total_booking_time()
duck_time = Booking.duck_booking_time(self)
if (all_time == None) or (duck_time == None):
return 0
return Booking.duck_booking_time(self) / Booking.total_booking_time()
def booked_by(self):
"""
Get the user who is currently using the duck
"""
booking_list = self.booking_set.filter(end_ts=None)
if len(booking_list) == 0:
return None
if len(booking_list) > 1:
raise RuntimeError(u"Duck is booked more than once!")
return booking_list[0].user
@python_2_unicode_compatible
class DuckName(models.Model):
"""
Model to hold name suggestions for Ducks
"""
duck = models.ForeignKey(Duck)
name = models.CharField(max_length=60, null=False)
suggested_by = models.ForeignKey(User)
suggested_at = models.DateTimeField(default=timezone.now)
closed_by = models.ForeignKey(User,
related_name='+',
null=True,
blank=True)
closed_at = models.DateTimeField(null=True, blank=True)
def __str__(self):
ret = "{0}, suggested by {1}".format(self.name,
self.suggested_by)
if self.closed_by:
ret += " <closed>"
return ret
@python_2_unicode_compatible
class DuckNameVote(models.Model):
"""
Model to hold votes to Duck names
"""
duck_name = models.ForeignKey(DuckName)
vote_timestamp = models.DateTimeField(default=timezone.now)
voter = models.ForeignKey(User)
upvote = models.BooleanField(default=True)
def __str__(self):
return "{0} voted {1} for {2}".format(self.voter,
"up" if self.upvote else "down",
self.duck_name)
@python_2_unicode_compatible
class DuckCompetence(models.Model):
"""
Duck competence governor table
"""
duck = models.ForeignKey(Duck, related_name='competences')
comp = models.ForeignKey(Competence, related_name='ducks')
up_minutes = models.IntegerField(default=0)
down_minutes = models.IntegerField(default=0)
def level(self):
"""
Return the actual level of a duck
"""
return minutes_to_level(self.up_minutes, self.down_minutes)
def __str__(self):
return "{0} with +{1}/-{2} minutes in {3}".format(self.duck,
self.up_minutes,
self.down_minutes,
self.comp)
class Meta:
unique_together = ('duck', 'comp')
@python_2_unicode_compatible
class Booking(models.Model):
"""
Duck booking governor table
"""
duck = models.ForeignKey(Duck)
user = models.ForeignKey(User)
comp_req = models.ForeignKey(Competence)
start_ts = models.DateTimeField(default=timezone.now)
end_ts = models.DateTimeField(null=True, blank=True)
successful = models.BooleanField(default=True)
@classmethod
def total_booking_time(cls):
"""
Get the sum of booked hours for all ducks
"""
return cls.objects.filter(
start_ts__isnull=False,
end_ts__isnull=False).extra(
select={
'amount': 'sum(strftime(%s, end_ts) - strftime(%s, start_ts))'
},
select_params=('%s', '%s'))[0].amount
@classmethod
def duck_booking_time(cls, duck):
"""
Get the sum of booked hours of a duck
"""
return cls.objects.filter(
start_ts__isnull=False,
end_ts__isnull=False, duck=duck).extra(
select={
'amount': 'sum(strftime(%s, end_ts) - strftime(%s, start_ts))'
},
select_params=('%s', '%s'))[0].amount
def __str__(self):
return "{0} booked by {1} for {2} since {3}".format(self.duck,
self.user,
self.comp_req,
self.start_ts)