diff --git a/products/context_processors.py b/products/context_processors.py index ffca5a3..8a34ae7 100644 --- a/products/context_processors.py +++ b/products/context_processors.py @@ -3,6 +3,7 @@ from products.models import ProductCategory def product_search_form(request): + #@TODO: APPLY SEARCH IN THE CONTEXT OF CHOSSEN DIRECTORY left_product_search_form = ProductSearchForm(submit_css_class='left-menu__search-btn') content_product_search_form = ProductSearchForm(submit_css_class='content__search-btn') if ProductSearchForm.form_action.__str__() in request.path and request.GET.get('name'): @@ -14,4 +15,9 @@ def product_search_form(request): def product_root_categories(request): - return {'product_root_categories': ProductCategory.objects.get_root_categories()} + current_category = request.resolver_match.kwargs.get('category_slug',None) + current_category = ProductCategory.objects.filter(slug=current_category).first() + return { + 'product_categories': ProductCategory.active.get_categories(current_category), + 'the_product_category' : current_category + } diff --git a/products/forms.py b/products/forms.py index 113d678..17daf2e 100644 --- a/products/forms.py +++ b/products/forms.py @@ -32,18 +32,21 @@ from crispy_forms.layout import Layout, Field, Button from django import forms from crispy_forms.helper import FormHelper +from django.forms import formset_factory from django.urls import reverse_lazy from django.utils.translation import ugettext_lazy as _ -from .models import Product +from .models import Product, ProductAttribute class ProductFilterForm(forms.Form): - pass + def __init__(self, *args,**kwargs): + super().__init__(*args,**kwargs) + class ProductSearchForm(forms.ModelForm): field_template = 'bootstrap/forms/product_search.html' - form_action = reverse_lazy('products:product_search') + form_action = reverse_lazy('products:product_list') submit_css_class = None def __init__(self, *args, **kwargs): @@ -61,3 +64,5 @@ class ProductSearchForm(forms.ModelForm): class Meta: model = Product fields = ['name'] + +inline_product_filter_formset = formset_factory(ProductFilterForm,extra=ProductAttribute.objects.all(),can_order=True,can_delete=False) diff --git a/products/models.py b/products/models.py index 6e92e2d..db133d9 100644 --- a/products/models.py +++ b/products/models.py @@ -12,7 +12,7 @@ from mptt import ( from mptt.models import MPTTModel, TreeForeignKey from autoslug import AutoSlugField -from core.models import AbstractStatusModel, ActualOnlyManager, AbstractDateTimeModel +from core.models import AbstractStatusModel, ActualOnlyManager, AbstractDateTimeModel, ActiveOnlyManager # ---------------------------------- COMMON PRODUCT STATUS ---------------------------------------# # Create your models here. @@ -41,7 +41,7 @@ PRODUCT_ATTRIBUTE_TYPE_CHOICES = ( PRODUCT_ATTRIBUTE_TYPE_DEFAULT = PRODUCT_ATTRIBUTE_TYPE_NONE -class ProductAttributeManager(models.Manager): +class ProductAttributeManager(ActiveOnlyManager): def get_range_type_attributes(self, product=None): pass @@ -90,18 +90,26 @@ class Manufacturer(AbstractStatusModel): class ProductCategoryManager(mptt_managers.TreeManager, ActualOnlyManager): - def get_root_categories(self): - return self.get_queryset().all() + def get_categories(self, parent=None): + return self.get_queryset().filter(parent=parent).all() + + +class ProductActiveCategoryManager(mptt_models.TreeManager, ActiveOnlyManager): + def get_categories(self, parent=None): + return self.get_queryset().filter(parent=parent).all() class ProductCategory(MPTTModel, AbstractStatusModel): - name = models.CharField(db_index=True, unique=True, max_length=64, blank=True, null=True, default=None) - slug = AutoSlugField(populate_from='name') - parent = TreeForeignKey('self', on_delete=models.CASCADE, null=True, blank=True, related_name='children') - image = models.ImageField(upload_to='categories', blank=True, verbose_name="image of category") + name = models.CharField(_('название'), db_index=True, unique=True, max_length=64, blank=True, null=True, + default=None) + slug = AutoSlugField(_('slug'), populate_from='name') + parent = TreeForeignKey('self', verbose_name=_('родительская категория'), on_delete=models.CASCADE, null=True, + blank=True, related_name='children') + image = models.ImageField(_("иконка"), upload_to='categories', blank=True) status = models.SmallIntegerField(_('статус'), default=STATUS_DEFAULT, choices=STATUS_CHOICES) objects = ProductCategoryManager() + active = ProductActiveCategoryManager() def __str__(self): return self.name @@ -199,7 +207,7 @@ class ProductImage(AbstractStatusModel): }) product = models.ForeignKey(Product, on_delete=models.CASCADE) - status = models.SmallIntegerField(_('Статус'),choices=STATUS_CHOICES, default=STATUS_DEFAULT) + status = models.SmallIntegerField(_('Статус'), choices=STATUS_CHOICES, default=STATUS_DEFAULT) filename = models.CharField(_('Имя файла'), max_length=255) image = models.FileField(_('Изображение'), upload_to=get_file_path, max_length=500) is_default = models.BooleanField(_('По умолчанию'), default=False) diff --git a/products/urls.py b/products/urls.py index 5f50893..1d58244 100644 --- a/products/urls.py +++ b/products/urls.py @@ -20,9 +20,12 @@ from .models import ProductCategory urlpatterns = [ - re_path(r'^search/$', views.ProductSearchView.as_view(), name='product_search'), - re_path(r'^product/(?P\w+)/$', views.ProductDetailsView.as_view(), name='product_details'), - re_path(r'^category/list/$', views.ProductCategoryListView.as_view(), name='product_category'), + + re_path(r'^list/$', views.ProductListView.as_view(), name='product_list'), + re_path(r'^list/(?P\w+)/$', views.ProductListView.as_view(),name='product_list'), + + re_path(r'^(?P\w+)/$', views.ProductDetailsView.as_view(), name='product_details'), + # Uncomment for elasticsearch # url(r'^autocomplete/$', autocomplete), diff --git a/products/views.py b/products/views.py index 9649381..f6b0201 100644 --- a/products/views.py +++ b/products/views.py @@ -7,6 +7,7 @@ from django.contrib import auth from django.utils.translation import ugettext_lazy as _ from django.views.generic import ListView, DetailView +from core.views import ProtectedListView from .models import ( Manufacturer,Product,ProductCategory ) @@ -24,69 +25,57 @@ class ProductDetailsView(DetailView): template_name = 'products/product_detail.html' -class ProductSearchView(ListView): - model = Product - template_name = 'products/product_search.html' - context_object_name = 'products' - paginate_by = settings.DEFAULT_PAGE_AMOUNT - title = _('Поиск товара') - - def get_queryset(self): - queryset = super().get_queryset() - if self.kwargs.get('name'): - queryset = queryset.filter(name__icontains=self.kwargs.get('name')) - return queryset - - def get_context_data(self, *, object_list=None, **kwargs): - context = super().get_context_data(object_list=object_list, **kwargs) - context['title'] = self.title + ":" + self.request.GET.get('name', '') - return context - - class ProductListView(ListView): model = Product + form = ProductSearchForm template_name = 'products/product_list.html' context_object_name = 'products' paginate_by = settings.DEFAULT_PAGE_AMOUNT title = _('Список товаров') + def get_title(self): + if self.request.GET.get('name'): + return _('Поиск товара') + ":" + self.request.GET.get('name') + title = _('Список товаров') + if self.request.resolver_match.kwargs.get('category_slug'): + return title + ":" + self.request.resolver_match.kwargs.get('category_slug') + return title + + def get_queryset(self): queryset = super().get_queryset() + if self.kwargs.get('name'): + queryset = queryset.filter(name__icontains=self.kwargs.get('name')) return queryset def get_context_data(self, *, object_list=None, **kwargs): context = super().get_context_data(object_list=object_list, **kwargs) - context['title'] = self.title + context['title'] = self.get_title() return context -class ProductCategoryListView(ListView): - model = ProductCategory - template_name = 'products/product_category_list.html' - - # Uncomment for elasticsearch # from .layout import FacetedProductSearchForm # from haystack.generic_views import FacetedSearchView as BaseFacetedSearchView # from haystack.query import SearchQuerySet -def serialize_decimal(obj): - if isinstance(obj, decimal.Decimal): - return str(obj) - return json.JSONEncoder.default(obj) - - -def producerslist(request): - username = auth.get_user(request).username - # category = None - # categories = ProductCategory.objects.filter(level__lte=0) - # products = Product.objects.filter(is_active=True) - producers = Manufacturer.objects.filter(is_active=True) - # if category_slug: - # category = get_object_or_404(ProductCategory, slug=category_slug) - # products = products.filter(category__in=category.get_descendants(include_self=True)) - return render(request, 'products/list.html', locals()) +# def serialize_decimal(obj): +# if isinstance(obj, decimal.Decimal): +# return str(obj) +# return json.JSONEncoder.default(obj) +# +# +# def producerslist(request): +# username = auth.get_user(request).username +# # category = None +# # categories = ProductCategory.objects.filter(level__lte=0) +# # products = Product.objects.filter(is_active=True) +# producers = Manufacturer.objects.filter(is_active=True) +# # if category_slug: +# # category = get_object_or_404(ProductCategory, slug=category_slug) +# # products = products.filter(category__in=category.get_descendants(include_self=True)) +# return render(request, 'products/list.html', locals()) # def categorieslist(request, producer_slug, category_slug=None): # username = accounts_ext.get_user(request).username