sort products by availability

remotes/origin/mitri4
Dmitriy Shesterkin 9 years ago
parent 41654885d3
commit 518a3228d1
  1. 2
      store/managers.py
  2. 135
      store/models.py
  3. 15
      store/queryset.py
  4. 18
      store/views.py

@ -1,2 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-

@ -5,6 +5,7 @@ from django.db.models import Count, Min, Sum
from accounts.models import Profile from accounts.models import Profile
from main.models import STARS_CHOICES from main.models import STARS_CHOICES
from store.alemtat import alemtat_get_cities_tuple, alemtat_get_services_tuple from store.alemtat import alemtat_get_cities_tuple, alemtat_get_services_tuple
from store.queryset import ProductQuerySet
FIELD_TYPE_CHAR = 'char' FIELD_TYPE_CHAR = 'char'
FIELD_TYPE_INT = 'int' FIELD_TYPE_INT = 'int'
@ -24,6 +25,7 @@ def photo_filename(instance, filename):
return 'photo_uploads/' + slugify_filename(filename) return 'photo_uploads/' + slugify_filename(filename)
class CartModel(models.Model): class CartModel(models.Model):
cart_id = models.CharField('Сессия', max_length=256, default='') cart_id = models.CharField('Сессия', max_length=256, default='')
profile = models.ForeignKey(Profile, default=None, null=True, blank=False, profile = models.ForeignKey(Profile, default=None, null=True, blank=False,
@ -32,6 +34,7 @@ class CartModel(models.Model):
weight = models.CharField('Вес', max_length=20, default='0') weight = models.CharField('Вес', max_length=20, default='0')
total = models.CharField('Итого тенге', max_length=20, default='0') total = models.CharField('Итого тенге', max_length=20, default='0')
class Category(models.Model): class Category(models.Model):
title = models.CharField('Наименование', max_length=256, default='') title = models.CharField('Наименование', max_length=256, default='')
h1 = models.CharField('Заголовок h1', max_length=256, default='', null=True, blank=True) h1 = models.CharField('Заголовок h1', max_length=256, default='', null=True, blank=True)
@ -40,14 +43,14 @@ class Category(models.Model):
meta_text = models.TextField('Мета текст', default='', null=True, blank=True) meta_text = models.TextField('Мета текст', default='', null=True, blank=True)
slug = models.SlugField('Ссылка', max_length=256, default='') slug = models.SlugField('Ссылка', max_length=256, default='')
description = models.TextField( description = models.TextField(
'Описание', default='', null=True, blank=True) 'Описание', default='', null=True, blank=True)
parent = models.ForeignKey( parent = models.ForeignKey(
'self', default=None, null=True, blank=True, related_name='childs', 'self', default=None, null=True, blank=True, related_name='childs',
verbose_name='Родительская категория') verbose_name='Родительская категория')
hide_products = models.BooleanField('Показывать дочерние категории вместо товаров', default=False) hide_products = models.BooleanField('Показывать дочерние категории вместо товаров', default=False)
image = models.ImageField('Картинка', upload_to=photo_filename, default=None, null=True, blank=True) image = models.ImageField('Картинка', upload_to=photo_filename, default=None, null=True, blank=True)
attributes = models.ManyToManyField( attributes = models.ManyToManyField(
'Attribute', through='AttributeForCategory') 'Attribute', through='AttributeForCategory')
priority = models.IntegerField('Приоритет', default=0) priority = models.IntegerField('Приоритет', default=0)
class Meta: class Meta:
@ -91,13 +94,18 @@ class Category(models.Model):
def brands(self): def brands(self):
brand_qs = self.get_all_products().values( brand_qs = self.get_all_products().values(
'brand').annotate(count_brands=Count('brand')) 'brand').annotate(count_brands=Count('brand'))
brand_pks = [v['brand'] for v in brand_qs] brand_pks = [v['brand'] for v in brand_qs]
return Brand.objects.filter(pk__in=brand_pks).order_by('title') return Brand.objects.filter(pk__in=brand_pks).order_by('title')
def get_childs_ordered_by_count(self): def get_childs_ordered_by_count(self):
return self.childs.annotate(Count('childs')).order_by('priority') # , '-childs__count') return self.childs.annotate(Count('childs')).order_by('priority') # , '-childs__count')
def get_all_products_in_stock_order_by(self, field):
queryset = Product.objects.filter(categories__in=self.get_all_childs()).sorted_in_stock_by_field(field)
return queryset
class Attribute(models.Model): class Attribute(models.Model):
title = models.CharField('Наименование', max_length=256, default='') title = models.CharField('Наименование', max_length=256, default='')
@ -113,15 +121,15 @@ class Attribute(models.Model):
class AttributeForCategory(models.Model): class AttributeForCategory(models.Model):
category = models.ForeignKey( category = models.ForeignKey(
Category, verbose_name='Категория', related_name='attr_cat') Category, verbose_name='Категория', related_name='attr_cat')
attribute = models.ForeignKey( attribute = models.ForeignKey(
Attribute, verbose_name='Атрибут в категории', Attribute, verbose_name='Атрибут в категории',
related_name='for_category') related_name='for_category')
field_type = models.CharField( field_type = models.CharField(
'Тип атрибута', choices=FIELD_TYPE_CHOICES, 'Тип атрибута', choices=FIELD_TYPE_CHOICES,
default='char', max_length=10) default='char', max_length=10)
choises_array = ArrayField( choises_array = ArrayField(
models.CharField(max_length=50), blank=True, default=[]) models.CharField(max_length=50), blank=True, default=[])
priority = models.IntegerField('Приоритет', default=0) priority = models.IntegerField('Приоритет', default=0)
class Meta: class Meta:
@ -131,12 +139,12 @@ class AttributeForCategory(models.Model):
def __str__(self): def __str__(self):
if self.field_type == FIELD_TYPE_SELECT: if self.field_type == FIELD_TYPE_SELECT:
return '{}: {} ({}: {})'.format( return '{}: {} ({}: {})'.format(
self.category.title, self.attribute.title, self.category.title, self.attribute.title,
self.get_field_type_display(), self.choises_array) self.get_field_type_display(), self.choises_array)
else: else:
return '{}: {} ({})'.format( return '{}: {} ({})'.format(
self.category.title, self.attribute.title, self.category.title, self.attribute.title,
self.get_field_type_display()) self.get_field_type_display())
def get_posible_values(self): def get_posible_values(self):
retval = [] retval = []
@ -176,17 +184,19 @@ class Product(models.Model):
title = models.CharField('Наименование', max_length=256, default='') title = models.CharField('Наименование', max_length=256, default='')
slug = models.SlugField('Ссылка', max_length=256, default='') slug = models.SlugField('Ссылка', max_length=256, default='')
categories = models.ManyToManyField( categories = models.ManyToManyField(
Category, verbose_name='Категории', related_name='products') Category, verbose_name='Категории', related_name='products')
description = models.TextField( description = models.TextField(
'Описание', default='', null=True, blank=True) 'Описание', default='', null=True, blank=True)
brand = models.ForeignKey(Brand, verbose_name='Брэнд') brand = models.ForeignKey(Brand, verbose_name='Брэнд')
video = models.CharField('Код Youtube', max_length=256, default='', null=True, blank=True) video = models.CharField('Код Youtube', max_length=256, default='', null=True, blank=True)
attirbutes = models.ManyToManyField( attirbutes = models.ManyToManyField(
AttributeForCategory, through='AttributesInProduct') AttributeForCategory, through='AttributesInProduct')
is_leader = models.BooleanField('Лидер продаж', default=False) is_leader = models.BooleanField('Лидер продаж', default=False)
on_main = models.BooleanField('На главной', default=False) on_main = models.BooleanField('На главной', default=False)
priority = models.IntegerField('Приоритет для главной', default=0) priority = models.IntegerField('Приоритет для главной', default=0)
objects = ProductQuerySet.as_manager()
class Meta: class Meta:
verbose_name = 'товар' verbose_name = 'товар'
verbose_name_plural = 'товары' verbose_name_plural = 'товары'
@ -254,14 +264,14 @@ class Product(models.Model):
class ProductVariation(models.Model): class ProductVariation(models.Model):
product = models.ForeignKey( product = models.ForeignKey(
Product, verbose_name='Товар', related_name='variations') Product, verbose_name='Товар', related_name='variations')
variation = models.CharField('Вариация', max_length=512, default='') variation = models.CharField('Вариация', max_length=512, default='')
price = models.IntegerField( price = models.IntegerField(
'Цена (тенге)', default=0, null=False, blank=False) 'Цена (тенге)', default=0, null=False, blank=False)
in_stock = models.IntegerField( in_stock = models.IntegerField(
'В наличии (шт.)', default=1, null=False, blank=False) 'В наличии (шт.)', default=1, null=False, blank=False)
article = models.CharField( article = models.CharField(
'Артикул', max_length=32, null=True, blank=True, default='') 'Артикул', max_length=32, null=True, blank=True, default='')
weight = models.FloatField('Вес (кг)', default=0.1, null=False, blank=False) weight = models.FloatField('Вес (кг)', default=0.1, null=False, blank=False)
discount = models.IntegerField('Скидка %', default=0, blank=False, null=False) discount = models.IntegerField('Скидка %', default=0, blank=False, null=False)
delivery_date = models.CharField('Дата доставки', default=None, blank=True, null=True, max_length=20) delivery_date = models.CharField('Дата доставки', default=None, blank=True, null=True, max_length=20)
@ -274,10 +284,11 @@ class ProductVariation(models.Model):
return self.variation return self.variation
def get_price(self, profile=None): def get_price(self, profile=None):
#import pdb; pdb.set_trace() # import pdb; pdb.set_trace()
#from django.core.mail import mail_admins # from django.core.mail import mail_admins
#mail_admins('auth', '{} {}'.format(profile, self.product.brand.slug)) # mail_admins('auth', '{} {}'.format(profile, self.product.brand.slug))
if profile and profile.is_authenticated() and self.product.brand.slug in ['beuchat', 'scorpena'] and profile.sale: if profile and profile.is_authenticated() and self.product.brand.slug in ['beuchat',
'scorpena'] and profile.sale:
return int(self.price - (self.price / Decimal(100) * Decimal(profile.sale))) return int(self.price - (self.price / Decimal(100) * Decimal(profile.sale)))
else: else:
if self.discount: if self.discount:
@ -291,12 +302,12 @@ class ProductVariation(models.Model):
class AttributesInProduct(models.Model): class AttributesInProduct(models.Model):
attribute = models.ForeignKey( attribute = models.ForeignKey(
AttributeForCategory, verbose_name='Атрибут в категории', AttributeForCategory, verbose_name='Атрибут в категории',
related_name='in_product') related_name='in_product')
product = models.ForeignKey( product = models.ForeignKey(
Product, verbose_name='Товар', related_name='product_attributes') Product, verbose_name='Товар', related_name='product_attributes')
value = models.CharField( value = models.CharField(
'Значение', max_length=64, default=None, blank=True, null=True) 'Значение', max_length=64, default=None, blank=True, null=True)
class Meta: class Meta:
verbose_name = 'атрибут в товаре' verbose_name = 'атрибут в товаре'
@ -310,7 +321,7 @@ class SlugImageField(models.ImageField):
class ImageInProduct(models.Model): class ImageInProduct(models.Model):
image = models.ImageField('Картинка', upload_to=photo_filename) image = models.ImageField('Картинка', upload_to=photo_filename)
product = models.ForeignKey( product = models.ForeignKey(
Product, verbose_name='Товар', related_name='images') Product, verbose_name='Товар', related_name='images')
is_main = models.BooleanField('Главная', default=False) is_main = models.BooleanField('Главная', default=False)
class Meta: class Meta:
@ -331,22 +342,22 @@ STATUS_CHOICES = (
) )
KAZPOST_CITIES = ( KAZPOST_CITIES = (
(1, "Астана"), (1, "Астана"),
(2, "Актобе"), (2, "Актобе"),
(3, "Актау"), (3, "Актау"),
(4, "Алматы"), (4, "Алматы"),
(5, "Атырау"), (5, "Атырау"),
(6, "Караганда"), (6, "Караганда"),
(7, "Кызылорда"), (7, "Кызылорда"),
(8, "Кокшетау"), (8, "Кокшетау"),
(9, "Костанай"), (9, "Костанай"),
(10, "Павлодар"), (10, "Павлодар"),
(11, "Петропавловск"), (11, "Петропавловск"),
(12, "Тараз"), (12, "Тараз"),
(13, "Усть-Каменогорск"), (13, "Усть-Каменогорск"),
(14, "Уральск"), (14, "Уральск"),
(15, "Шымкент"), (15, "Шымкент"),
(16, "Талдыкорган") (16, "Талдыкорган")
) )
@ -356,28 +367,28 @@ class OrderData(models.Model):
profile = models.ForeignKey(Profile, default=None, null=True, blank=False, profile = models.ForeignKey(Profile, default=None, null=True, blank=False,
related_name='orders') related_name='orders')
first_name = models.CharField( first_name = models.CharField(
'Имя', max_length=64, blank=False, null=False) 'Имя', max_length=64, blank=False, null=False)
last_name = models.CharField( last_name = models.CharField(
'Фамилия', max_length=64, blank=False, null=False) 'Фамилия', max_length=64, blank=False, null=False)
phone = models.CharField( phone = models.CharField(
'Номер мобильного телефона', max_length=15, blank=False, null=False) 'Номер мобильного телефона', max_length=15, blank=False, null=False)
email = models.EmailField( email = models.EmailField(
'Email', blank=False, null=False) 'Email', blank=False, null=False)
city = models.CharField( city = models.CharField(
'Город Алемтат', max_length=20, blank=True, null=True, choices=alemtat_get_cities_tuple()) 'Город Алемтат', max_length=20, blank=True, null=True, choices=alemtat_get_cities_tuple())
deliv_service = models.CharField( deliv_service = models.CharField(
'Почтовая служба', max_length=20, blank=True, null=True, default='alemtat') 'Почтовая служба', max_length=20, blank=True, null=True, default='alemtat')
kazpost_city = models.IntegerField( kazpost_city = models.IntegerField(
'Город Казпочта', blank=True, null=True, choices=KAZPOST_CITIES) 'Город Казпочта', blank=True, null=True, choices=KAZPOST_CITIES)
address = models.CharField( address = models.CharField(
'Адрес', max_length=100, blank=False, null=False) 'Адрес', max_length=100, blank=False, null=False)
deliv_type = models.CharField( deliv_type = models.CharField(
'Способ Алемтат', max_length=2, blank=True, null=True, default='', 'Способ Алемтат', max_length=2, blank=True, null=True, default='',
choices=alemtat_get_services_tuple()) choices=alemtat_get_services_tuple())
items = models.CharField( items = models.CharField(
'Товары', max_length=256, blank=False, null=False, default='') 'Товары', max_length=256, blank=False, null=False, default='')
amount = models.FloatField( amount = models.FloatField(
'Сумма', blank=False, null=False, default=0.0) 'Сумма', blank=False, null=False, default=0.0)
status = models.IntegerField('Статус', default=0, null=False, blank=False, status = models.IntegerField('Статус', default=0, null=False, blank=False,
choices=STATUS_CHOICES) choices=STATUS_CHOICES)
@ -387,9 +398,9 @@ class OrderData(models.Model):
def __str__(self): def __str__(self):
return '{} {}: {}'.format( return '{} {}: {}'.format(
self.first_name, self.first_name,
self.last_name, self.last_name,
self.amount self.amount
) )
def get_status(self): def get_status(self):

@ -0,0 +1,15 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from django.db import models
class ProductQuerySet(models.QuerySet):
def sorted_in_stock_by_field(self, field):
queryset = self.extra(select={
'have_stock':
'CASE WHEN (SELECT MAX(in_stock) FROM store_productvariation ' +
'WHERE store_productvariation.product_id = store_product.id) = 0 ' +
'THEN 0 ELSE 1 END'
}).order_by('-have_stock', field)
return queryset

@ -98,25 +98,33 @@ class CategoryView(CategoryBaseView, TemplateView):
pass pass
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
retval = super(CategoryView, self).get_context_data() retval = super(CategoryView, self).get_context_data()
q = None q = None
if self.is_search: if self.is_search:
q = self.request.GET.get('q', '') q = self.request.GET.get('q', '')
self.products_qs = Product.objects.filter(title__icontains=q).order_by('-pk') self.products_qs = Product.objects.filter(title__icontains=q).\
sorted_in_stock_by_field('-pk')
brands_pks = [item.brand.pk for item in self.products_qs] brands_pks = [item.brand.pk for item in self.products_qs]
retval['brands'] = Brand.objects.filter(pk__in=brands_pks).order_by( retval['brands'] = Brand.objects.filter(pk__in=brands_pks).order_by(
'title') # list(set(map(lambda item: item.brand, self.products_qs))) 'title') # list(set(map(lambda item: item.brand, self.products_qs)))
elif self.is_sale: elif self.is_sale:
self.products_qs = Product.objects.filter(variations__discount__gt=0).distinct().order_by('-pk') self.products_qs = Product.objects.filter(variations__discount__gt=0).distinct().\
sorted_in_stock_by_field('-pk')
brands_pks = [item.brand.pk for item in self.products_qs] brands_pks = [item.brand.pk for item in self.products_qs]
retval['brands'] = Brand.objects.filter(pk__in=brands_pks).order_by('title') retval['brands'] = Brand.objects.filter(pk__in=brands_pks).order_by('title')
elif self.is_leaders: elif self.is_leaders:
brands_pks = [item.brand.pk for item in self.products_qs] brands_pks = [item.brand.pk for item in self.products_qs]
retval['brands'] = Brand.objects.filter(pk__in=brands_pks).order_by('title') retval['brands'] = Brand.objects.filter(pk__in=brands_pks).order_by('title')
else: else:
self.category = self._get_full_category(kwargs['categories']) self.category = self._get_full_category(kwargs['categories'])
if not self.category.hide_products: if not self.category.hide_products:
self.products_qs = self.category.get_all_products().order_by('-pk') self.products_qs = self.category.get_all_products_in_stock_order_by('-pk')
self.brand_pks = self._get_brand_pks() self.brand_pks = self._get_brand_pks()
self.sort = self._get_sort() self.sort = self._get_sort()
@ -137,10 +145,10 @@ class CategoryView(CategoryBaseView, TemplateView):
'= store_product.id' '= store_product.id'
}) })
self.products_qs = preordered_qs.order_by(sort_parameter) self.products_qs = preordered_qs.order_by('-have_stock', sort_parameter)
self._get_filter_attributes() self._get_filter_attributes()
# print(self.products_qs.query)
self.paginate() self.paginate()
retval['category'] = self.category retval['category'] = self.category
retval['products'] = self.products_qs retval['products'] = self.products_qs

Loading…
Cancel
Save