0
0 комментариев
from __future__ import unicode_literals
 
from django.contrib.contenttypes.models import ContentType
from django.db import models
from django.db.models import Q
from django.urls import reverse
from image_cropping import ImageRatioField
from orderable.models import Orderable
from eav.models import Entity
from icmgeneric.base import GenericPage
from django.utils.translation import ugettext_lazy as _
 
class Product(GenericPage):
name = models.CharField(max_length=256, verbose_name=_('Name'))
annotation = models.TextField(null=True, blank=True, verbose_name=_('Annotation'))
category = models.ForeignKey(Category, null=True, verbose_name=_('Category'))
price = models.DecimalField(null=True, verbose_name=_('Price'), max_digits=6, decimal_places=2)
old_price = models.DecimalField(null=True, blank=True, verbose_name=_('Old price'), max_digits=6, decimal_places=2)
discount = models.IntegerField(null=True, blank=True, verbose_name=_('Discount'))
in_new_products_list = models.BooleanField(default=False, verbose_name=_('In new products list'))
in_stock = models.BooleanField(default=True, verbose_name=_('In stock'))
active = models.BooleanField(default=True, verbose_name=_('Active'))
 
@property
def entity(self):
    return Entity(self)
 
@property
def values(self):
    return self.entity.get_values()
 
def get_values_for_detail(self):
    dc = {}
 
    for value in self.values:
        if value.attribute.name not in dc.keys():
            dc[value.attribute.name] = [value.value]
        else:
            dc[value.attribute.name].append(value.value)
 
    return dc
 
def get_absolute_url(self):
    return reverse('catalog:detail', args=[self.category.slug, self.slug])
 
def get_attributes(self):
    attr_list = []
    for item in self.values:
        attr_list.append(item.attribute)
    return attr_list
 
def get_filters(self):
    return self.values.filter(Q(active=True) & Q(in_filter_list=True))
 
def get_filters_values(self):
    filters = []
    for filter in self.values.filter(Q(active=True) & Q(in_filter_list=True)):
        filters.append(filter.value)
    return filters
 
def get_photos(self):
    return self.photoitem_set.filter(active=True)
 
def __unicode__(self):
    return self.name
 
class Meta:
    ordering = ['name']
    verbose_name = _('Product')
    verbose_name_plural = _('Products')
 
eav.register(Product)

это модели свойств и значений для сущностей

class Attribute(models.Model):
    class Meta:
        ordering = ['content_type', 'name']
        unique_together = ('site', 'content_type', 'slug')
        verbose_name, verbose_name_plural = _('Attribute'), _('Attributes')
 
    TYPE_TEXT = 'text'
    TYPE_FLOAT = 'float'
    TYPE_INT = 'int'
    TYPE_DATE = 'date'
    TYPE_BOOLEAN = 'bool'
    # TYPE_OBJECT = 'object'
    # TYPE_ENUM = 'enum'
 
    DATATYPE_CHOICES = (
        (TYPE_TEXT, _(u"Text")),
        (TYPE_FLOAT, _(u"Float")),
        (TYPE_INT, _(u"Integer")),
        (TYPE_DATE, _(u"Date")),
        (TYPE_BOOLEAN, _(u"True / False")),
        # (TYPE_OBJECT, _(u"Django Object")),
        # (TYPE_ENUM, _(u"Multiple Choice")),
    )
 
    name = models.CharField(max_length=100,
                            help_text=_(u"User-friendly attribute name"), verbose_name=_(u'name'))
 
    content_type = models.ForeignKey(ContentType, blank=True, null=True, verbose_name=_(u"content type"))
    site = models.ForeignKey(Site, verbose_name=_(u"site"), default=settings.SITE_ID)
 
    slug = EavSlugField(max_length=50, db_index=True, help_text=_(u"Short unique attribute label"),
                        verbose_name=_(u'slug'))
 
    description = models.CharField(max_length=256, blank=True, null=True, help_text=_(u"Short description"),
                                   verbose_name=_(u'description'))
 
    # enum_group = models.ForeignKey(EnumGroup, verbose_name=_(u"choice group"), blank=True, null=True)
    # type = models.CharField(_(u"type"), max_length=20, blank=True, null=True)
 
    @property
    def help_text(self):
        return self.description
 
    datatype = EavDatatypeField(max_length=6, choices=DATATYPE_CHOICES, verbose_name=_(u"data type"))
    created = models.DateTimeField(default=timezone.now, editable=False, verbose_name=_(u"created"))
    modified = models.DateTimeField(auto_now=True, verbose_name=_(u"modified"))
    required = models.BooleanField(default=False, verbose_name=_(u"required"))
    display_order = models.PositiveIntegerField(default=1, verbose_name=_(u"display order"))
    active = models.BooleanField(default=True, verbose_name=_('Active'))
 
    objects = models.Manager()
    on_site = CurrentSiteManager()
 
    def get_validators(self):
        '''
        Returns the appropriate validator function from :mod:`~eav.validators`
        as a list (of length one) for the datatype.
 
        .. note::
           The reason it returns it as a list, is eventually we may want this
           method to look elsewhere for additional attribute specific
           validators to return as well as the default, built-in one.
        '''
        DATATYPE_VALIDATORS = {
            'text': validate_text,
            'float': validate_float,
            'int': validate_int,
            'date': validate_date,
            'bool': validate_bool,
            'object': validate_object,
            'enum': validate_enum,
        }
 
        validation_function = DATATYPE_VALIDATORS[self.datatype]
        return [validation_function]
 
    # def validate_value(self, value):
    #     '''
    #     Check *value* against the validators returned by
    #     :meth:`get_validators` for this attribute.
    #     '''
    #     for validator in self.get_validators():
    #         validator(value)
    #     if self.datatype == self.TYPE_ENUM:
    #         if value not in self.enum_group.enums.all():
    #             raise ValidationError(_(u"%(enum)s is not a valid choice "
    #                                     u"for %(attr)s") % \
    #                                    {'enum': value, 'attr': self})
 
    def save(self, *args, **kwargs):
        '''
        Saves the Attribute and auto-generates a slug field if one wasn't
        provided.
        '''
        if not self.slug:
            self.slug = EavSlugField.create_slug_from_name(self.name)
        self.full_clean()
        super(Attribute, self).save(*args, **kwargs)
 
    # def clean(self):
    #     '''
    #     Validates the attribute.  Will raise ``ValidationError`` if
    #     the attribute's datatype is *TYPE_ENUM* and enum_group is not set,
    #     or if the attribute is not *TYPE_ENUM* and the enum group is set.
    #     '''
    #     if self.datatype == self.TYPE_ENUM and not self.enum_group:
    #         raise ValidationError(_(
    #             u"You must set the choice group for multiple choice" \
    #             u"attributes"))
    #
    #     if self.datatype != self.TYPE_ENUM and self.enum_group:
    #         raise ValidationError(_(
    #             u"You can only assign a choice group to multiple choice " \
    #             u"attributes"))
 
    # def get_choices(self):
    #     '''
    #     Returns a query set of :class:`EnumValue` objects for this attribute.
    #     Returns None if the datatype of this attribute is not *TYPE_ENUM*.
    #     '''
    #     if not self.datatype == Attribute.TYPE_ENUM:
    #         return None
    #     return self.enum_group.enums.all()
 
    def save_value(self, entity, value):
        '''
        Called with *entity*, any django object registered with eav, and
        *value*, the :class:`Value` this attribute for *entity* should
        be set to.
 
        If a :class:`Value` object for this *entity* and attribute doesn't
        exist, one will be created.
 
        .. note::
           If *value* is None and a :class:`Value` object exists for this
            Attribute and *entity*, it will delete that :class:`Value` object.
        '''
        ct = ContentType.objects.get_for_model(entity)
        try:
            value_obj = self.value_set.get(entity_ct=ct,
                                           entity_id=entity.pk,
                                           attribute=self)
        except Value.DoesNotExist:
            if value == None or value == '':
                return
            value_obj = Value.objects.create(entity_ct=ct,
                                             entity_id=entity.pk,
                                             attribute=self)
        if value == None or value == '':
            value_obj.delete()
            return
 
        if value != value_obj.value:
            value_obj.value = value
            value_obj.save()
 
    def __unicode__(self):
        return u"%s.%s (%s)" % (self.content_type, self.name, self.get_datatype_display())
 
 
class Value(models.Model):
    entity_ct = models.ForeignKey(ContentType, related_name='value_entities', verbose_name=_(u'Entity'))
    entity_id = models.IntegerField(verbose_name=_(u'Entity Code'))
    entity = generic.GenericForeignKey(ct_field='entity_ct', fk_field='entity_id')
 
    attribute = models.ForeignKey(Attribute, db_index=True, verbose_name=_(u"Attribute"))
    value_text = models.TextField(blank=True, null=True, verbose_name=_(u"Text Value"))
    value_float = models.FloatField(blank=True, null=True, verbose_name=_(u"Float Value"))
    value_int = models.IntegerField(blank=True, null=True, verbose_name=_(u"Integer Value"))
    value_date = models.DateTimeField(blank=True, null=True, verbose_name=_(u"Date Value"))
    value_bool = models.NullBooleanField(blank=True, null=True, verbose_name=_(u"True/False Value"))
    # value_enum = models.ForeignKey(EnumValue, blank=True, null=True, related_name='eav_values')
    # generic_value_id = models.IntegerField(blank=True, null=True)
    # generic_value_ct = models.ForeignKey(ContentType, blank=True, null=True, related_name='value_values')
    # value_object = generic.GenericForeignKey(ct_field='generic_value_ct', fk_field='generic_value_id')
    created = models.DateTimeField(_(u"created"), default=timezone.now)
    modified = models.DateTimeField(_(u"modified"), auto_now=True)
    active = models.BooleanField(default=True, verbose_name=_('Active'))
    in_filter_list = models.BooleanField(default=False, verbose_name=_('In filter list'))
 
    def save(self, *args, **kwargs):
        '''
        Validate and save this value
        '''
        self.full_clean()
        super(Value, self).save(*args, **kwargs)
 
    # def clean(self):
    #     '''
    #     Raises ``ValidationError`` if this value's attribute is *TYPE_ENUM*
    #     and value_enum is not a valid choice for this value's attribute.
    #     '''
    #     if self.attribute.datatype == Attribute.TYPE_ENUM and \
    #        self.value_enum:
    #         if self.value_enum not in self.attribute.enum_group.enums.all():
    #             raise ValidationError(_(u"%(choice)s is not a valid " \
    #                                     u"choice for %s(attribute)") % \
    #                                     {'choice': self.value_enum,
    #                                      'attribute': self.attribute})
 
    def get_count(self):
        dc = {'eav__' + self.attribute.slug: self.value}
        return self.entity.__class__.objects.filter(Q(**dc)).count()
 
    def _get_value(self):
        '''
        Return the python object this value is holding
        '''
        return getattr(self, 'value_%s' % self.attribute.datatype)
 
    def _set_value(self, new_value):
        '''
        Set the object this value is holding
        '''
        setattr(self, 'value_%s' % self.attribute.datatype, new_value)
 
    value = property(_get_value, _set_value)
 
    def __unicode__(self):
        return u"%s - %s: \"%s\"" % (self.entity, self.attribute.name,
                                     self.value)
 
    class Meta:
        verbose_name, verbose_name_plural = _(u'Value'), _(u'Values')

Добавил в админке свойство color и type для Product

Потом делаю к примеру такой запрос:

qs = Product.objects.filter(Q(name='name_1') & Q(name='name_2'))

И не находит ни одного объекта. Подскажите в чем дело.

Изменен статус публикации
Добавить комментарий