from autoslug import AutoSlugField from django.contrib.auth import get_user_model from django.db import models from django.utils.translation import ugettext_lazy as _ from mptt.models import TreeForeignKey from core.models import AbstractStatusModel, AbstractDateTimeModel, AbstractStatusMPTTModel # ---------------------------------- COMMON PRODUCT STATUS ---------------------------------------# STATUS_INACTIVE = 0 STATUS_ACTIVE = 25 STATUS_DELETED = 50 STATUS_DEFAULT = STATUS_ACTIVE STATUS_CHOICES = ( (STATUS_INACTIVE, _('Неактивный')), (STATUS_ACTIVE, _('Активный')), (STATUS_DELETED, _('Удаленный')), ) # --------------------------------- PRODUCT ATTRIBUTE STATTUS------------------------------------# # PRODUCT_ATTRIBUTE_TYPE_NONE = 0 # PRODUCT_ATTRIBUTE_TYPE_RANGE = 25 # PRODUCT_ATTRIBUTE_TYPE_SELECT = 50 # PRODUCT_ATTRIBUTE_TYPE_CHECKBOX = 75 # PRODUCT_ATTRIBUTE_TYPE_INPUT = 100 # # PRODUCT_ATTRIBUTE_TYPE_CHOICES = ( # (PRODUCT_ATTRIBUTE_TYPE_NONE, _('отсуствует')), # (PRODUCT_ATTRIBUTE_TYPE_RANGE, _('диапазон')), # (PRODUCT_ATTRIBUTE_TYPE_SELECT, _('выбор из списка')), # (PRODUCT_ATTRIBUTE_TYPE_CHECKBOX, _('мн. выбор из списка')), # (PRODUCT_ATTRIBUTE_TYPE_INPUT, _('значение'), # ) # ) # PRODUCT_ATTRIBUTE_TYPE_DEFAULT = PRODUCT_ATTRIBUTE_TYPE_NONE # class ProductAttributeManager(ActiveOnlyManager): # def get_range_type_attributes(self, product=None): # pass # # def get_select_type_attributes(self, product=None): # pass # # def get_all_type_attributes(self): # pass # # @TODO: tranlsate into english and use traslation # class ProductAttribute(AbstractStatusModel): # name = models.CharField(_('название'), max_length=64) # slug = AutoSlugField(populate_from='name', verbose_name=_('код'), help_text="поисковый код аттрибута,по котором возможен поиск") # type = models.SmallIntegerField(_('тип'), choices=PRODUCT_ATTRIBUTE_TYPE_CHOICES, # default=PRODUCT_ATTRIBUTE_TYPE_DEFAULT) # status = models.SmallIntegerField(_('статус'), default=STATUS_DEFAULT, choices=STATUS_CHOICES) # main_attribute = models.BooleanField(_('основной атрибут'), default=False, help_text=_('будет отображен рядом с товаром при отображении в списке')) # # objects = ProductAttributeManager() # # def __str__(self): # return self.name # # class Meta: # ordering = ('slug',) # verbose_name = _('Аттрибут продукта') # verbose_name_plural = _('Аттрибуты продукта') class Manufacturer(AbstractStatusModel): name = models.CharField(_('название'), max_length=256, blank=False, null=False) slug = AutoSlugField(verbose_name=_('код'), unique=True, populate_from='name') image = models.ImageField(_('изображение'), upload_to='producers', blank=False, null=False) status = models.SmallIntegerField(_('статус'), default=STATUS_DEFAULT, choices=STATUS_CHOICES) def __str__(self): return self.name class Meta: verbose_name = _('Производитель') verbose_name_plural = _('Производители') # @TODO: tranlsate into english and use traslation class ProductCategory(AbstractStatusMPTTModel): def get_file_path(self, filename): return "products/{category}/{filename}".format(**{ 'category': self.slug, 'filename': filename }) name = models.CharField(_('название'), db_index=True, unique=True, max_length=64) slug = AutoSlugField(_('код'), populate_from='name') parent = TreeForeignKey('self', verbose_name=_('родительская категория'), on_delete=models.CASCADE, null=True, blank=True, related_name='children') image = models.FileField(_("иконка"), upload_to=get_file_path, blank=False, null=False) status = models.SmallIntegerField(_('статус'), default=STATUS_DEFAULT, choices=STATUS_CHOICES) def __str__(self): return self.name @property def viewname(self): return 'products:product_list' @property def viewname_kwargs(self): return {'path': self.get_path()} class MPTTMeta: order_insertion_by = ('name',) class Meta: unique_together = (_('slug'), _('parent')) ordering = (_('tree_id'), _('level')) verbose_name = _("Категория") verbose_name_plural = _("Категории") # @TODO: translate into english and use translation class Product(AbstractStatusMPTTModel): name = models.CharField(_('имя'), max_length=64, db_index=True) slug = AutoSlugField(_('slug'), populate_from='name', db_index=True) description = models.TextField(_('описание'), blank=True, null=True, default=None) manufacturer = models.ForeignKey(Manufacturer, verbose_name=_('производитель'), on_delete=models.SET_NULL, blank=True, null=True) parent = TreeForeignKey(ProductCategory, verbose_name=_('категория'), on_delete=models.SET_NULL, blank=True, null=True, help_text="Категория") platform = models.CharField(_('Платформа'), max_length=255, null=True, blank=True) status = models.SmallIntegerField(_('статус'), default=STATUS_DEFAULT, choices=STATUS_CHOICES) def __str__(self): return self.name @property def viewname(self): return 'products:product_details' @property def viewname_kwargs(self): return {'path': self.parent.get_path() + self.get_path()} class MPTTMeta: order_insertion_by = ('name',) class Meta: indexes = [ models.Index(fields=['id', 'slug']) ] verbose_name = _('Продукт') verbose_name_plural = _('Продукты') class ProductRate(AbstractDateTimeModel): user = models.ForeignKey(get_user_model(), on_delete=models.CASCADE) product = models.ForeignKey(Product, on_delete=models.CASCADE) rate = models.PositiveSmallIntegerField(_('оценка'), default=0) class Meta: verbose_name = _('Рейтинг продукта') verbose_name_plural = _('Рейтинг продукта') # ----------------- PRODUCT IMAGE STATUS LIST ------------------ class ProductImageManager(models.Manager): def get_default_image(self): return self.get_queryset().filter(product=self.instance, is_default=True).first() def get_all_images(self): return self.get_queryset().filter(product=self.instance).order_by('-is_default').all() def get_all_images_except_default(self): return self.get_queryset().filter(product=self.instance, is_default=False).all() class ProductImage(AbstractDateTimeModel): def get_file_path(self, filename): return "products/{product}/{filename}".format(**{ 'product': self.product.slug, 'filename': filename }) product = models.ForeignKey(Product, on_delete=models.CASCADE) filename = models.CharField(_('имя файла'), max_length=255) image = models.FileField(_('изображение'), upload_to=get_file_path, max_length=500) is_default = models.BooleanField(_('по умолчанию'), default=False) objects = ProductImageManager() @classmethod def create(cls, request, file): product_image = cls(request=request, file=file, filename=file.name) return product_image def __str__(self): return self.filename def save(self, force_insert=False, force_update=False, using=None, update_fields=None): if not self.product.productimage_set.count(): self.is_default = True elif self.is_default: self.product.productimage_set.update(is_default=False) self.filename = self.image.name return super().save(force_insert, force_update, using, update_fields) class Meta: verbose_name = _('Изображение продукта') verbose_name_plural = _('Изображения продукта')