説明なし

models.py 3.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. # -*- coding: utf-8 -*-
  2. from __future__ import unicode_literals
  3. from django.db import models
  4. from django.core.exceptions import ValidationError, NON_FIELD_ERRORS
  5. from django.db.utils import IntegrityError
  6. from django.utils.text import Truncator
  7. import re
  8. #import logging
  9. #logger = logging.getLogger('console')
  10. unique_constraint_re = re.compile(r'^UNIQUE\s+constraint\s+failed:(.*)$', re.IGNORECASE)
  11. class ModelEx(models.Model):
  12. class Meta:
  13. abstract = True
  14. def get_duplicate_key_error_dict(self, fields):
  15. return {NON_FIELD_ERRORS: 'Duplicate value for %s' % ', '.join(fields)}
  16. def save(self, *args, **kwargs):
  17. try:
  18. super(ModelEx, self).save(*args, **kwargs)
  19. except IntegrityError as e:
  20. match = unique_constraint_re.search(e.message)
  21. if match:
  22. fields = [x.strip().split('.')[-1] for x in match.group(1).split(',')]
  23. raise ValidationError(self.get_duplicate_key_error_dict(fields))
  24. else:
  25. raise
  26. class FeedCategory(ModelEx):
  27. name = models.CharField(max_length=50, unique=True)
  28. description = models.CharField(max_length=255, blank=True)
  29. days_required = models.PositiveIntegerField(default=366)
  30. starting_month = models.PositiveIntegerField(
  31. default=1,
  32. choices=(
  33. (1, 'January'),
  34. (2, 'February'),
  35. (3, 'March'),
  36. (4, 'April'),
  37. (5, 'May'),
  38. (6, 'June'),
  39. (7, 'July'),
  40. (8, 'August'),
  41. (9, 'September'),
  42. (10, 'October'),
  43. (11, 'November'),
  44. (12, 'December')
  45. )
  46. )
  47. class Meta:
  48. verbose_name = 'Category'
  49. verbose_name_plural = 'Categories'
  50. def get_duplicate_key_error_dict(self, fields):
  51. if fields[0] == 'name':
  52. return {'name': 'There is already a category with this name'}
  53. else:
  54. return super(FeedCategory, self).get_duplicate_key_error_dict(fields)
  55. @property
  56. def status(self):
  57. last_day = 0
  58. total_missing = 0
  59. missing_days = []
  60. for item in FeedItem.objects.filter(feed_category=self).order_by('feed_category_id', 'day_number'):
  61. day = item.day_number
  62. missing_count = day - last_day - 1
  63. total_missing += missing_count
  64. # The unique key and order_by on FeedItem ensure that missing_count
  65. # cannot be less than 0.
  66. if missing_count == 1:
  67. missing_days.append(str(day - 1))
  68. elif missing_count > 1:
  69. missing_days.append('{0}-{1}'.format(last_day + 1, day - 1))
  70. last_day = day
  71. missing_count = self.days_required - last_day
  72. if missing_count > 0:
  73. total_missing += missing_count
  74. if missing_count == 1:
  75. missing_days.append(str(self.days_required))
  76. elif missing_count > 1:
  77. missing_days.append('{0}-{1}'.format(last_day + 1, self.days_required))
  78. if missing_days:
  79. return "WARNING: Missing {0} day{1}: {2}".format(total_missing, '' if total_missing == 1 else 's', ', '.join(missing_days))
  80. else:
  81. return "Complete"
  82. def __unicode__(self):
  83. return self.name
  84. class FeedItem(ModelEx):
  85. feed_category = models.ForeignKey(FeedCategory, on_delete=models.CASCADE)
  86. day_number = models.PositiveIntegerField()
  87. message_text = models.CharField(max_length=160)
  88. class Meta:
  89. verbose_name = 'Item'
  90. verbose_name_plural = 'Items'
  91. unique_together = ('feed_category', 'day_number')
  92. def get_duplicate_key_error_dict(self, fields):
  93. return {'day_number': 'There is already an item with this day number'}
  94. def __unicode__(self):
  95. return u'{0}: {1}'.format(self.day_number, Truncator(self.message_text).chars(20))