from django.conf import settings from django.urls import reverse_lazy from django.utils.translation import ugettext_lazy as _ from django.db import models from mptt import ( models as mptt_models, managers as mptt_managers, ) # Create your models here. STATUS_NEW = 0 STATUS_ACTIVE = 25 STATUS_DELETED = 50 STATUS_DEFAULT = STATUS_NEW STATUS_CHOICES = ( (STATUS_NEW, _('Новый')), (STATUS_ACTIVE, _('Активный')), (STATUS_DELETED, _('Удаленный')), ) class CaseInsensitiveQuerySet(models.QuerySet): CASE_INSENSITIVE_FIELDS = ('email',) def _filter_or_exclude(self, negate, *args, **kwargs): for field in self.CASE_INSENSITIVE_FIELDS: if field in kwargs: kwargs[field + '__iexact'] = kwargs[field] del kwargs[field] return super()._filter_or_exclude(negate, *args, **kwargs) class ActualOnlyManager(models.Manager): def get_queryset(self): queryset = super().get_queryset() if not settings.DEBUG: queryset = queryset.exclude(status=STATUS_DELETED) return queryset class ActiveOnlyManager(models.Manager): def get_queryset(self): return super().get_queryset().filter(status=STATUS_ACTIVE) class DeletedManager(models.Manager): def get_queryset(self): return super().get_queryset().filter(status=STATUS_DELETED) class ActualOnlyTreeManager(mptt_managers.TreeManager, ActualOnlyManager): _base_manager = None class ActiveOnlyTreeManager(mptt_managers.TreeManager, ActiveOnlyManager): _base_manager = None class DeletedTreeManager(mptt_managers.TreeManager, DeletedManager): _base_manager = None class AbstractDateTimeModel(models.Model): create_at = models.DateTimeField(_('создан в'), auto_now_add=True) updated_at = models.DateTimeField(_('обновлен'), auto_now=True) class Meta: abstract = True # @TODO: translate into english and use translation class AbstractStatusModel(AbstractDateTimeModel): status = models.SmallIntegerField(_('статус'), default=STATUS_DEFAULT, choices=STATUS_CHOICES) objects = ActualOnlyManager() deleted = DeletedManager() active = ActiveOnlyManager() @property def is_active(self): return self.status == STATUS_ACTIVE @is_active.setter def is_active(self, value): if value: self.status = STATUS_ACTIVE else: self.status = STATUS_DEFAULT def delete(self, using=None, keep_parents=False): self.status = STATUS_DELETED self.save(using=using) def delete_from_base(self, using=None, keep_parents=False): return super().delete(using, keep_parents) class Meta: abstract = True class AbstractStatusMPTTModel(mptt_models.MPTTModel, AbstractStatusModel): objects = ActualOnlyTreeManager() deleted = DeletedTreeManager() active = ActiveOnlyTreeManager() @property def viewname(self): raise NotImplementedError @property def viewname_kwargs(self): raise NotImplementedError def get_absolute_url(self): return reverse_lazy(self.viewname, kwargs=self.viewname_kwargs) class Meta: abstract = True class Currency(AbstractDateTimeModel): name = models.CharField(_('название'), max_length=255) code = models.CharField(_('код валюты'), max_length=64) sign = models.CharField(_('символ валюты'), max_length=10, blank=True, null=True) value = models.DecimalField(_('Курс'), max_digits=6, decimal_places=2, help_text=_('Указывается в рублях')) def __str__(self): return self.name class Meta: verbose_name = _('Валюта') verbose_name_plural = _('Валюта') class City(AbstractDateTimeModel): name = models.CharField(_('Город'), max_length=255) class Meta: verbose_name = _('Город') verbose_name_plural = _('Города') class Certificate(AbstractStatusModel): def upload_file_to(self, filename): return "certificates/{filename}".format(**{ 'category': self.name, 'filename': filename }) name = models.CharField(_('Название'), max_length=255) image = models.FileField(_('Изображение'), upload_to=upload_file_to, blank=True, null=True) preview = models.FileField(_('Миниатюрка'), upload_to=upload_file_to) class Meta: verbose_name = _('Сертификат') verbose_name_plural = _('Сертификаты')