parent
17b21e6dbe
commit
8a94098546
12 changed files with 1153 additions and 0 deletions
@ -0,0 +1,195 @@ |
|||||||
|
# from django.contrib import admin |
||||||
|
# from import_export import resources, fields, widgets |
||||||
|
# from import_export.admin import ImportExportModelAdmin |
||||||
|
# from .models import * |
||||||
|
# |
||||||
|
# class CustomModelResource(resources.ModelResource): |
||||||
|
# def before_import_row(self, row, **kwargs): |
||||||
|
# """ |
||||||
|
# Override to add additional logic. Does nothing by default. |
||||||
|
# """ |
||||||
|
# try: |
||||||
|
# row['attributes'] = eval(row['attributes']) |
||||||
|
# except: |
||||||
|
# try: |
||||||
|
# row['discount_policy'] = eval(row['discount_policy']) |
||||||
|
# except: |
||||||
|
# pass |
||||||
|
# |
||||||
|
# class CustomManyToManyWidget(widgets.ManyToManyWidget): |
||||||
|
# def clean(self, value, row=None, *args, **kwargs): |
||||||
|
# t1 = super(CustomManyToManyWidget, self).clean(value) |
||||||
|
# return self.model.objects.get(name=t1) if t1 else None |
||||||
|
# |
||||||
|
# |
||||||
|
# # class CustomForeignKeyWidget(widgets.ForeignKeyWidget): |
||||||
|
# # def clean(self, value, row=None, *args, **kwargs): |
||||||
|
# # return self.model.objects.get_or_create(name=value)[0] |
||||||
|
# |
||||||
|
# # class ProductImageInline(admin.TabularInline): |
||||||
|
# # model = ProductImage |
||||||
|
# # extra = 0 |
||||||
|
# |
||||||
|
# # class ProductAttributeInline(admin.TabularInline): |
||||||
|
# # model = ProductAttribute |
||||||
|
# # extra = 1 |
||||||
|
# # verbose_name_plural = 'ProductAttribute' |
||||||
|
# # suit_classes = 'suit-tab suit-tab-PA' |
||||||
|
# # |
||||||
|
# class AttributeChoiceValueInline(admin.TabularInline): |
||||||
|
# model = ProductAttributeChoiceValue |
||||||
|
# # prepopulated_fields = {'slug': ('name',)} |
||||||
|
# extra = 1 |
||||||
|
# verbose_name_plural = 'AttributeChoiceValue' |
||||||
|
# suit_classes = 'suit-tab suit-tab-ACV' |
||||||
|
# # |
||||||
|
# # class OfferInline(admin.TabularInline): |
||||||
|
# # model = Offer |
||||||
|
# # extra = 1 |
||||||
|
# # verbose_name_plural = 'Offers' |
||||||
|
# # suit_classes = 'suit-tab suit-tab-offers' |
||||||
|
# |
||||||
|
# class ProductCategoryAdmin(admin.ModelAdmin): |
||||||
|
# list_display = [field.name for field in ProductCategory._meta.fields] |
||||||
|
# |
||||||
|
# class Meta: |
||||||
|
# model = ProductCategory |
||||||
|
# |
||||||
|
# # class AttributeChoiceValueAdmin(admin.ModelAdmin): |
||||||
|
# # list_display = [field.name for field in ProductCategory._meta.fields] |
||||||
|
# # |
||||||
|
# # class Meta: |
||||||
|
# # model = AttributeChoiceValue |
||||||
|
# # |
||||||
|
# # admin.site.register(AttributeChoiceValue, AttributeChoiceValueAdmin) |
||||||
|
# |
||||||
|
# class ProductAttributeAdmin(admin.ModelAdmin): |
||||||
|
# list_display = [field.name for field in ProductAttribute._meta.fields] |
||||||
|
# inlines = [AttributeChoiceValueInline] |
||||||
|
# # prepopulated_fields = {'slug': ('name',)} |
||||||
|
# |
||||||
|
# suit_form_tabs = (('general', 'General'), |
||||||
|
# ('ACV', 'AttributeValues'),) |
||||||
|
# |
||||||
|
# class Meta: |
||||||
|
# model = ProductAttribute |
||||||
|
# |
||||||
|
# admin.site.register(ProductAttribute, ProductAttributeAdmin) |
||||||
|
# |
||||||
|
# @admin.register(Manufacturer) |
||||||
|
# class ProducerAdmin(admin.ModelAdmin): |
||||||
|
# list_display = [field.name for field in Manufacturer._meta.fields] |
||||||
|
# |
||||||
|
# |
||||||
|
# class ProductResource(CustomModelResource): |
||||||
|
# # id = fields.Field(default=generate_Jid(prefix='J'), |
||||||
|
# # readonly=True, |
||||||
|
# # widget=widgets.CharWidget(), |
||||||
|
# # ) |
||||||
|
# |
||||||
|
# name = fields.Field(column_name='name', attribute='name', |
||||||
|
# default=None, |
||||||
|
# widget=widgets.CharWidget(), |
||||||
|
# ) |
||||||
|
# # price = fields.Field(column_name='price', attribute='price', |
||||||
|
# # default=0, |
||||||
|
# # widget=widgets.DecimalWidget(), |
||||||
|
# # ) |
||||||
|
# description = fields.Field(column_name='description', attribute='description', |
||||||
|
# default=None, |
||||||
|
# widget=widgets.CharWidget(), |
||||||
|
# ) |
||||||
|
# |
||||||
|
# # producer = fields.Field(column_name='producer', attribute='producer', |
||||||
|
# # default=None, |
||||||
|
# # widget=widgets.CharWidget(), |
||||||
|
# # ) |
||||||
|
# |
||||||
|
# category = fields.Field(column_name='category', attribute='category', |
||||||
|
# default=None, |
||||||
|
# widget=widgets.ForeignKeyWidget(ProductCategory, field='name'), |
||||||
|
# ) |
||||||
|
# producer = fields.Field(column_name='producer', attribute='producer', |
||||||
|
# default=None, |
||||||
|
# widget=widgets.ForeignKeyWidget(Manufacturer, field='name'), |
||||||
|
# ) |
||||||
|
# attributes = fields.Field(column_name='attributes', attribute='attributes', |
||||||
|
# default=None, |
||||||
|
# widget=CustomManyToManyWidget(ProductAttribute, field="name"), |
||||||
|
# ) |
||||||
|
# is_active = fields.Field(column_name='is_active', attribute='is_active', |
||||||
|
# default=1, |
||||||
|
# widget=widgets.BooleanWidget()) |
||||||
|
# |
||||||
|
# discount_policy = fields.Field(column_name='discount_policy', attribute='discount_policy', |
||||||
|
# default={}, |
||||||
|
# widget=widgets.CharWidget()) |
||||||
|
# |
||||||
|
# # delete = fields.Field(column_name='delete', attribute='delete', |
||||||
|
# # default=0, |
||||||
|
# # widget=widgets.BooleanWidget()) |
||||||
|
# |
||||||
|
# # def for_delete(self, row, instance): |
||||||
|
# # return self.fields['delete'].clean(row) |
||||||
|
# |
||||||
|
# class Meta: |
||||||
|
# model = Product |
||||||
|
# fields = ('id', 'name', 'description', 'producer', 'category', 'is_active', 'attributes', 'discount_policy') |
||||||
|
# export_order = ('id', 'name', 'producer', 'is_active', 'category', 'attributes', 'description', 'discount_policy') |
||||||
|
# # import_id_fields = ('name',) |
||||||
|
# |
||||||
|
# def dehydrate_str_choices(self, obj): |
||||||
|
# if obj.id: |
||||||
|
# return obj.str_choices() |
||||||
|
# |
||||||
|
# @admin.register(Product) |
||||||
|
# class ProductAdmin(ImportExportModelAdmin): |
||||||
|
# list_display = ['id', 'name', 'category', 'manufacturer','status'] |
||||||
|
# # inlines = [OfferInline] |
||||||
|
# list_filter = ['status', 'create_at', 'updated_at', 'category'] |
||||||
|
# search_fields = ['name', 'id'] |
||||||
|
# |
||||||
|
# resource_class = ProductResource |
||||||
|
# |
||||||
|
# # class OfferResource(CustomModelResource): |
||||||
|
# # name = fields.Field(column_name='name', attribute='name', |
||||||
|
# # default=None, |
||||||
|
# # widget=widgets.CharWidget(), |
||||||
|
# # ) |
||||||
|
# # |
||||||
|
# # price = fields.Field(column_name='price', attribute='price', |
||||||
|
# # default=0, |
||||||
|
# # widget=widgets.DecimalWidget(), |
||||||
|
# # ) |
||||||
|
# # |
||||||
|
# # products = fields.Field(column_name='products', attribute='products', |
||||||
|
# # widget=widgets.ForeignKeyWidget(Product, field='name'), |
||||||
|
# # ) |
||||||
|
# # |
||||||
|
# # is_active = fields.Field(column_name='is_active', attribute='is_active', |
||||||
|
# # default=1, |
||||||
|
# # widget=widgets.BooleanWidget()) |
||||||
|
# # |
||||||
|
# # attributes = fields.Field(column_name='attributes', attribute='attributes', |
||||||
|
# # default={}, |
||||||
|
# # widget=widgets.CharWidget()) |
||||||
|
# # |
||||||
|
# # class Meta: |
||||||
|
# # model = Offer |
||||||
|
# # fields = ('name', 'products', 'price', 'is_active', 'attributes') |
||||||
|
# # export_order = ('name', 'products', 'attributes', 'is_active', 'price') |
||||||
|
# # import_id_fields = ('name',) |
||||||
|
# |
||||||
|
# # class OfferAdmin(ImportExportModelAdmin): |
||||||
|
# # list_display = ['id', 'name', 'products', 'price', 'is_active', 'attributes'] |
||||||
|
# # resource_class = OfferResource |
||||||
|
# # class ProductImageAdmin(admin.ModelAdmin): |
||||||
|
# # list_display = [field.name for field in ProductImage._meta.fields] |
||||||
|
# # |
||||||
|
# # class Meta: |
||||||
|
# # model = ProductImage |
||||||
|
# |
||||||
|
# # admin.site.register(ProductImage, ProductImageAdmin) |
||||||
|
# # admin.site.register(ProductCategory, ProductCategoryAdmin) |
||||||
|
# # admin.site.register(Product, ProductAdmin) |
||||||
|
# # admin.site.register(Offer, OfferAdmin) |
||||||
@ -0,0 +1,5 @@ |
|||||||
|
from django.apps import AppConfig |
||||||
|
|
||||||
|
|
||||||
|
class ProductsConfig(AppConfig): |
||||||
|
name = 'products' |
||||||
@ -0,0 +1,10 @@ |
|||||||
|
|
||||||
|
from products.forms import ProductSearchForm |
||||||
|
|
||||||
|
|
||||||
|
def product_search_form(request): |
||||||
|
return {'product_search_form': ProductSearchForm()} |
||||||
|
|
||||||
|
def product_root_categories(request): |
||||||
|
categories = {'product_root_categories': []} |
||||||
|
return categories |
||||||
@ -0,0 +1,533 @@ |
|||||||
|
[ |
||||||
|
{ |
||||||
|
"model": "products.productcategory", |
||||||
|
"pk": 1, |
||||||
|
"fields": { |
||||||
|
"name": "Information security", |
||||||
|
"slug": "information-security", |
||||||
|
"is_active": true, |
||||||
|
"parent": null, |
||||||
|
"lft": 1, |
||||||
|
"rght": 6, |
||||||
|
"tree_id": 2, |
||||||
|
"level": 0 |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
"model": "products.productcategory", |
||||||
|
"pk": 2, |
||||||
|
"fields": { |
||||||
|
"name": "Document manipulation", |
||||||
|
"slug": "document-manipulation", |
||||||
|
"is_active": true, |
||||||
|
"parent": null, |
||||||
|
"lft": 1, |
||||||
|
"rght": 4, |
||||||
|
"tree_id": 1, |
||||||
|
"level": 0 |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
"model": "products.productcategory", |
||||||
|
"pk": 3, |
||||||
|
"fields": { |
||||||
|
"name": "System software", |
||||||
|
"slug": "system-software", |
||||||
|
"is_active": true, |
||||||
|
"parent": null, |
||||||
|
"lft": 1, |
||||||
|
"rght": 6, |
||||||
|
"tree_id": 3, |
||||||
|
"level": 0 |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
"model": "products.productcategory", |
||||||
|
"pk": 4, |
||||||
|
"fields": { |
||||||
|
"name": "Anti-virus software", |
||||||
|
"slug": "anti-virus-software", |
||||||
|
"is_active": true, |
||||||
|
"parent": 1, |
||||||
|
"lft": 2, |
||||||
|
"rght": 3, |
||||||
|
"tree_id": 2, |
||||||
|
"level": 1 |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
"model": "products.productcategory", |
||||||
|
"pk": 5, |
||||||
|
"fields": { |
||||||
|
"name": "Data recovery", |
||||||
|
"slug": "data-recovery", |
||||||
|
"is_active": true, |
||||||
|
"parent": 1, |
||||||
|
"lft": 4, |
||||||
|
"rght": 5, |
||||||
|
"tree_id": 2, |
||||||
|
"level": 1 |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
"model": "products.productcategory", |
||||||
|
"pk": 6, |
||||||
|
"fields": { |
||||||
|
"name": "OS", |
||||||
|
"slug": "os", |
||||||
|
"is_active": true, |
||||||
|
"parent": 3, |
||||||
|
"lft": 4, |
||||||
|
"rght": 5, |
||||||
|
"tree_id": 3, |
||||||
|
"level": 1 |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
"model": "products.productcategory", |
||||||
|
"pk": 7, |
||||||
|
"fields": { |
||||||
|
"name": "DB", |
||||||
|
"slug": "db", |
||||||
|
"is_active": true, |
||||||
|
"parent": 3, |
||||||
|
"lft": 2, |
||||||
|
"rght": 3, |
||||||
|
"tree_id": 3, |
||||||
|
"level": 1 |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
"model": "products.productcategory", |
||||||
|
"pk": 8, |
||||||
|
"fields": { |
||||||
|
"name": "Microsoft Office", |
||||||
|
"slug": "microsoft-office", |
||||||
|
"is_active": true, |
||||||
|
"parent": 2, |
||||||
|
"lft": 2, |
||||||
|
"rght": 3, |
||||||
|
"tree_id": 1, |
||||||
|
"level": 1 |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
"model": "products.productattribute", |
||||||
|
"pk": 1, |
||||||
|
"fields": { |
||||||
|
"name": "License type", |
||||||
|
"slug": "license-type" |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
"model": "products.productattribute", |
||||||
|
"pk": 2, |
||||||
|
"fields": { |
||||||
|
"name": "License term", |
||||||
|
"slug": "license-term" |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
"model": "products.productattribute", |
||||||
|
"pk": 3, |
||||||
|
"fields": { |
||||||
|
"name": "Technical support", |
||||||
|
"slug": "technical-support" |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
"model": "products.productattribute", |
||||||
|
"pk": 4, |
||||||
|
"fields": { |
||||||
|
"name": "Number users", |
||||||
|
"slug": "number-users" |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
"model": "products.productattribute", |
||||||
|
"pk": 5, |
||||||
|
"fields": { |
||||||
|
"name": "Type of organization", |
||||||
|
"slug": "type-organization" |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
"model": "products.attributechoicevalue", |
||||||
|
"pk": 1, |
||||||
|
"fields": { |
||||||
|
"name": "New", |
||||||
|
"slug": "new", |
||||||
|
"attribute": 1 |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
"model": "products.attributechoicevalue", |
||||||
|
"pk": 2, |
||||||
|
"fields": { |
||||||
|
"name": "Prolongation", |
||||||
|
"slug": "prolongation", |
||||||
|
"attribute": 1 |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
"model": "products.attributechoicevalue", |
||||||
|
"pk": 3, |
||||||
|
"fields": { |
||||||
|
"name": "Migration", |
||||||
|
"slug": "migration", |
||||||
|
"attribute": 1 |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
"model": "products.attributechoicevalue", |
||||||
|
"pk": 4, |
||||||
|
"fields": { |
||||||
|
"name": "One year", |
||||||
|
"slug": "one-year", |
||||||
|
"attribute": 2 |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
"model": "products.attributechoicevalue", |
||||||
|
"pk": 5, |
||||||
|
"fields": { |
||||||
|
"name": "Two years", |
||||||
|
"slug": "two-years", |
||||||
|
"attribute": 2 |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
"model": "products.attributechoicevalue", |
||||||
|
"pk": 6, |
||||||
|
"fields": { |
||||||
|
"name": "Standard AAS", |
||||||
|
"slug": "standard-aas", |
||||||
|
"attribute": 3 |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
"model": "products.attributechoicevalue", |
||||||
|
"pk": 7, |
||||||
|
"fields": { |
||||||
|
"name": "Extended AAP", |
||||||
|
"slug": "extended-aap", |
||||||
|
"attribute": 3 |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
"model": "products.attributechoicevalue", |
||||||
|
"pk": 8, |
||||||
|
"fields": { |
||||||
|
"name": "from 1 to 49", |
||||||
|
"slug": "1-49", |
||||||
|
"attribute": 4 |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
"model": "products.attributechoicevalue", |
||||||
|
"pk": 9, |
||||||
|
"fields": { |
||||||
|
"name": "from 50 to 99", |
||||||
|
"slug": "50-99", |
||||||
|
"attribute": 4 |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
"model": "products.attributechoicevalue", |
||||||
|
"pk": 10, |
||||||
|
"fields": { |
||||||
|
"name": "from 100 to 299", |
||||||
|
"slug": "100-299", |
||||||
|
"attribute": 4 |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
"model": "products.attributechoicevalue", |
||||||
|
"pk": 11, |
||||||
|
"fields": { |
||||||
|
"name": "Version Upgrade", |
||||||
|
"slug": "version-upgrade", |
||||||
|
"attribute": 1 |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
"model": "products.attributechoicevalue", |
||||||
|
"pk": 12, |
||||||
|
"fields": { |
||||||
|
"name": "commercial", |
||||||
|
"slug": "commercial", |
||||||
|
"attribute": 5 |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
"model": "products.attributechoicevalue", |
||||||
|
"pk": 13, |
||||||
|
"fields": { |
||||||
|
"name": "educational", |
||||||
|
"slug": "educational", |
||||||
|
"attribute": 5 |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
"model": "products.productclass", |
||||||
|
"pk": 1, |
||||||
|
"fields": { |
||||||
|
"name": "Antivirus software class", |
||||||
|
"has_variants": true, |
||||||
|
"variant_attributes": [ |
||||||
|
2, |
||||||
|
1, |
||||||
|
5 |
||||||
|
] |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
"model": "products.productclass", |
||||||
|
"pk": 2, |
||||||
|
"fields": { |
||||||
|
"name": "Data recovery class", |
||||||
|
"has_variants": true, |
||||||
|
"variant_attributes": [ |
||||||
|
1, |
||||||
|
3 |
||||||
|
] |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
"model": "products.productclass", |
||||||
|
"pk": 3, |
||||||
|
"fields": { |
||||||
|
"name": "Document manipulation class", |
||||||
|
"has_variants": true, |
||||||
|
"variant_attributes": [] |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
"model": "products.productclass", |
||||||
|
"pk": 4, |
||||||
|
"fields": { |
||||||
|
"name": "DB class", |
||||||
|
"has_variants": true, |
||||||
|
"variant_attributes": [ |
||||||
|
2, |
||||||
|
4 |
||||||
|
] |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
"model": "products.productclass", |
||||||
|
"pk": 5, |
||||||
|
"fields": { |
||||||
|
"name": "OS class", |
||||||
|
"has_variants": true, |
||||||
|
"variant_attributes": [ |
||||||
|
5 |
||||||
|
] |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
"model": "products.product", |
||||||
|
"pk": 85, |
||||||
|
"fields": { |
||||||
|
"name": "Kaspersky Endpoint Security \u0434\u043b\u044f \u0431\u0438\u0437\u043d\u0435\u0441\u0430 CLOUD", |
||||||
|
"slug": "kaspersky-endpoint-security-dlya-biznesa-cloud", |
||||||
|
"price": "1730.00", |
||||||
|
"points": "173.00", |
||||||
|
"description": "Kaspersky Endpoint Security Cloud \u2013 \u044d\u0442\u043e \u0440\u0435\u0448\u0435\u043d\u0438\u0435, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u043f\u043e\u0442\u0440\u0435\u0431\u043d\u043e\u0441\u0442\u044f\u043c \u043c\u0430\u043b\u043e\u0433\u043e \u0431\u0438\u0437\u043d\u0435\u0441\u0430 \u0438 \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u0435\u0442 \u043d\u0430\u0434\u0435\u0436\u043d\u0443\u044e \u0437\u0430\u0449\u0438\u0442\u0443 \u043a\u043e\u043c\u043f\u044c\u044e\u0442\u0435\u0440\u043e\u0432, \u043c\u043e\u0431\u0438\u043b\u044c\u043d\u044b\u0445 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432 \u0438 \u0444\u0430\u0439\u043b\u043e\u0432\u044b\u0445 \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u0432 \u0438\u0437 \u043e\u0431\u043b\u0430\u0447\u043d\u043e\u0439 \u043a\u043e\u043d\u0441\u043e\u043b\u0438 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f. \u0420\u0435\u0448\u0435\u043d\u0438\u0435 \u043d\u0435 \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u043f\u043e\u043a\u0443\u043f\u043a\u0438 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0433\u043e \u043e\u0431\u043e\u0440\u0443\u0434\u043e\u0432\u0430\u043d\u0438\u044f \u0438 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0441\u0438\u0441\u0442\u0435\u043c\u043e\u0439 \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u0438 \u043a\u043e\u043c\u043f\u0430\u043d\u0438\u0438 \u0441 \u043b\u044e\u0431\u043e\u0433\u043e \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430, \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u043d\u043e\u0433\u043e \u043a \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0443.", |
||||||
|
"short_description": "", |
||||||
|
"producer": "Kaspersky", |
||||||
|
"image": "products/2017/05/26/thumb_1473758588.png", |
||||||
|
"discount": 0, |
||||||
|
"stock": 10, |
||||||
|
"category": 4, |
||||||
|
"product_class": 1, |
||||||
|
"is_active": true, |
||||||
|
"is_hit": false, |
||||||
|
"is_new": false, |
||||||
|
"created": "2017-05-26", |
||||||
|
"updated": "2017-07-07" |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
"model": "products.product", |
||||||
|
"pk": 86, |
||||||
|
"fields": { |
||||||
|
"name": "ESET NOD32 Antivirus Business Edition", |
||||||
|
"slug": "eset-nod32-antivirus-business-edition", |
||||||
|
"price": "2400.00", |
||||||
|
"points": "240.00", |
||||||
|
"description": "ESET Endpoint Antivirus \u2013 \u043d\u043e\u0432\u043e\u0435 \u0441\u043b\u043e\u0432\u043e \u0432 \u043f\u0440\u043e\u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0439 \u0437\u0430\u0449\u0438\u0442\u0435 \u043a\u043b\u0438\u0435\u043d\u0442\u0441\u043a\u0438\u0445 \u0440\u0430\u0431\u043e\u0447\u0438\u0445 \u0441\u0442\u0430\u043d\u0446\u0438\u0439 \u043e\u0442 \u043b\u044e\u0431\u043e\u0433\u043e \u0438\u0437 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043e\u0432 \u0432\u0440\u0435\u0434\u043e\u043d\u043e\u0441\u043d\u043e\u0433\u043e \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u043d\u043e\u0433\u043e \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0435\u043d\u0438\u044f. \u041f\u0440\u043e\u0434\u0443\u043a\u0442 \u0440\u0430\u0441\u0441\u0447\u0438\u0442\u0430\u043d \u043d\u0430 \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043a\u0443 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439, \u0437\u0430\u043f\u0440\u0435\u0449\u0435\u043d\u043d\u044b\u0445 \u0432 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430\u0445, \u0430 \u0442\u0430\u043a\u0436\u0435 \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u0435\u0442 \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u043a\u043e\u043d\u0444\u0438\u0434\u0435\u043d\u0446\u0438\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438. \u0421\u043e\u0447\u0435\u0442\u0430\u043d\u0438\u0435 \u0437\u0430\u043f\u0430\u0442\u0435\u043d\u0442\u043e\u0432\u0430\u043d\u043d\u043e\u0433\u043e \u043c\u0435\u0442\u043e\u0434\u0430 \u044d\u0432\u0440\u0438\u0441\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e \u0430\u043d\u0430\u043b\u0438\u0437\u0430 \u0438 \u043d\u043e\u0432\u0435\u0439\u0448\u0438\u0445 \u0438\u043d\u0442\u0435\u043b\u043b\u0435\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u044b\u0445 \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0439 \u043e\u0431\u043b\u0430\u0447\u043d\u043e\u0433\u043e \u0442\u0438\u043f\u0430 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043e\u043f\u0435\u0440\u0430\u0442\u0438\u0432\u043d\u043e \u0441\u043a\u0430\u043d\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0438 \u0440\u0430\u0441\u043f\u043e\u0437\u043d\u0430\u0432\u0430\u0442\u044c \u0432\u0441\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u044b\u0435 \u0442\u0438\u043f\u044b \u0443\u0433\u0440\u043e\u0437, \u0442\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0438\u0440\u0443\u044f \u043c\u043e\u043c\u0435\u043d\u0442\u0430\u043b\u044c\u043d\u043e\u0435 \u0440\u0435\u0430\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043d\u0430 \u043f\u043e\u043f\u044b\u0442\u043a\u0438 \u0432\u043d\u0435\u0434\u0440\u0435\u043d\u0438\u044f \u0432\u0440\u0435\u0434\u043e\u043d\u043e\u0441\u043d\u043e\u0433\u043e \u041f\u041e \u0432 \u043a\u043e\u0440\u043f\u043e\u0440\u0430\u0442\u0438\u0432\u043d\u0443\u044e \u0441\u0435\u0442\u044c.", |
||||||
|
"short_description": "", |
||||||
|
"producer": "Eset", |
||||||
|
"image": "products/2017/05/26/thumb_1381486034.jpg", |
||||||
|
"discount": 0, |
||||||
|
"stock": 10, |
||||||
|
"category": 4, |
||||||
|
"product_class": 1, |
||||||
|
"is_active": true, |
||||||
|
"is_hit": false, |
||||||
|
"is_new": false, |
||||||
|
"created": "2017-05-26", |
||||||
|
"updated": "2017-07-07" |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
"model": "products.product", |
||||||
|
"pk": 87, |
||||||
|
"fields": { |
||||||
|
"name": "Acronis Backup 12 Workstation License", |
||||||
|
"slug": "acronis-backup-12-workstation-license", |
||||||
|
"price": "3190.00", |
||||||
|
"points": "319.00", |
||||||
|
"description": "\u041e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438\r\n\r\n\u0411\u044b\u0441\u0442\u0440\u043e\u0435 \u0432\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0445 \u0441\u0438\u0441\u0442\u0435\u043c, \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439, \u0444\u0430\u0439\u043b\u043e\u0432 \u0438 \u0434\u0430\u043d\u043d\u044b\u0445\r\n\r\n \u0411\u044b\u0441\u0442\u0440\u043e\u0435 \u0438 \u043f\u0440\u043e\u0441\u0442\u043e\u0435 \u0440\u0435\u0437\u0435\u0440\u0432\u043d\u043e\u0435 \u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0438 \u0432\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u043f\u043e\u043b\u043d\u043e\u0433\u043e \u043e\u0431\u0440\u0430\u0437\u0430 \u0434\u0438\u0441\u043a\u0430\r\n \u0423\u0434\u043e\u0431\u043d\u043e\u0435 \u0432\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \"\u043d\u0430 \u0433\u043e\u043b\u043e\u0435 \u0436\u0435\u043b\u0435\u0437\u043e\" \u043d\u0430 \u0442\u043e\u043c \u0436\u0435 \u0438\u043b\u0438 \u043e\u0442\u043b\u0438\u0447\u0430\u044e\u0449\u0435\u043c\u0441\u044f \u043e\u0431\u043e\u0440\u0443\u0434\u043e\u0432\u0430\u043d\u0438\u0438, \u043b\u0438\u0431\u043e \u043d\u0430 \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0439 \u043c\u0430\u0448\u0438\u043d\u0435\r\n \u0420\u0435\u0437\u0435\u0440\u0432\u043d\u043e\u0435 \u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0438 \u0432\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0445 \u043f\u0430\u043f\u043e\u043a \u043d\u0430 \u0434\u0438\u0441\u043a\u0435 \u0438\u043b\u0438 \u0441\u0435\u0442\u0435\u0432\u044b\u0445 \u043f\u0430\u043f\u043e\u043a \u043e\u0431\u0449\u0435\u0433\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f\r\n \u0412\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0445 \u0444\u0430\u0439\u043b\u043e\u0432 \u0438 \u043f\u0430\u043f\u043e\u043a \u0438\u0437 \u0440\u0435\u0437\u0435\u0440\u0432\u043d\u043e\u0439 \u043a\u043e\u043f\u0438\u0438 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u043e\u0431\u0440\u0430\u0437\u0430\r\n \u041f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0440\u0435\u0437\u0435\u0440\u0432\u043d\u044b\u0445 \u043a\u043e\u043f\u0438\u0439 \u0432 \u0444\u043e\u0440\u043c\u0430\u0442 \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u044b\u0445 \u043c\u0430\u0448\u0438\u043d", |
||||||
|
"short_description": "", |
||||||
|
"producer": "Acronis", |
||||||
|
"image": "products/2017/05/26/thumb_1384933473.jpg", |
||||||
|
"discount": 0, |
||||||
|
"stock": 10, |
||||||
|
"category": 5, |
||||||
|
"product_class": 2, |
||||||
|
"is_active": true, |
||||||
|
"is_hit": false, |
||||||
|
"is_new": false, |
||||||
|
"created": "2017-05-26", |
||||||
|
"updated": "2017-07-07" |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
"model": "products.product", |
||||||
|
"pk": 88, |
||||||
|
"fields": { |
||||||
|
"name": "Symantec System Recovery Desktop", |
||||||
|
"slug": "symantec-system-recovery-desktop", |
||||||
|
"price": "3830.00", |
||||||
|
"points": "383.00", |
||||||
|
"description": "Symantec System Recovery 2013 \u2013 \u044d\u0442\u043e \u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u0434\u043b\u044f \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u043e\u0433\u043e \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0440\u0435\u0437\u0435\u0440\u0432\u043d\u044b\u0445 \u043a\u043e\u043f\u0438\u0439 \u0438 \u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u044f \u0432\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0440\u0430\u0431\u043e\u0447\u0438\u0445 \u0441\u0442\u0430\u043d\u0446\u0438\u0439 \u0438 \u043d\u043e\u0443\u0442\u0431\u0443\u043a\u043e\u0432 \u0432 \u0430\u0432\u0430\u0440\u0438\u0439\u043d\u044b\u0445 \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u044f\u0445, \u0447\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043c\u0438\u043d\u0438\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432\u0440\u0435\u043c\u044f \u043f\u0440\u043e\u0441\u0442\u043e\u044f \u0438 \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e \u0431\u044b\u0441\u0442\u0440\u043e \u0432\u0435\u0440\u043d\u0443\u0442\u044c\u0441\u044f \u043a \u0440\u0435\u0448\u0435\u043d\u0438\u044e \u0440\u0430\u0431\u043e\u0447\u0438\u0445 \u0437\u0430\u0434\u0430\u0447.\r\n\r\n\u0422\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u044f Restore Anyware, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u0430\u044f \u0432 \u043f\u0440\u043e\u0434\u0443\u043a\u0442\u0435, \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u0435\u0442 \u0441\u0438\u0441\u0442\u0435\u043c\u043d\u044b\u043c \u0430\u0434\u043c\u0438\u043d\u0438\u0441\u0442\u0440\u0430\u0442\u043e\u0440\u0430\u043c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u043e \u0440\u0435\u0448\u0430\u0442\u044c \u0432\u043e\u043f\u0440\u043e\u0441 \u043e \u0432\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0438 \u0442\u043e\u0433\u043e, \u0447\u0435\u0433\u043e \u043d\u0443\u0436\u043d\u043e, \u0432 \u043d\u0443\u0436\u043d\u043e\u0435 \u0432\u0440\u0435\u043c\u044f \u0438 \u0432 \u043d\u0443\u0436\u043d\u043e\u043c \u043c\u0435\u0441\u0442\u0435. \u0414\u0430\u043d\u043d\u0430\u044f \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u044f \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0432\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0444\u0430\u0439\u043b\u044b, \u043f\u0430\u043f\u043a\u0438 \u0438 \u043e\u0431\u044a\u0435\u043a\u0442\u044b \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439, \u043d\u043e \u0438 \u043a\u043e\u043c\u043f\u044c\u044e\u0442\u0435\u0440 \u0446\u0435\u043b\u0438\u043a\u043e\u043c, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f \u0442\u043e \u0436\u0435 \u0441\u0430\u043c\u043e\u0435 \u0438\u043b\u0438 \u043d\u043e\u0432\u043e\u0435 \u043e\u0431\u043e\u0440\u0443\u0434\u043e\u0432\u0430\u043d\u0438\u0435.", |
||||||
|
"short_description": "", |
||||||
|
"producer": "Symantec", |
||||||
|
"image": "products/2017/05/26/thumb_1401701995.png", |
||||||
|
"discount": 0, |
||||||
|
"stock": 5, |
||||||
|
"category": 5, |
||||||
|
"product_class": 2, |
||||||
|
"is_active": true, |
||||||
|
"is_hit": false, |
||||||
|
"is_new": false, |
||||||
|
"created": "2017-05-26", |
||||||
|
"updated": "2017-07-07" |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
"model": "products.product", |
||||||
|
"pk": 89, |
||||||
|
"fields": { |
||||||
|
"name": "Microsoft Windows 10 Professional GetGenuine", |
||||||
|
"slug": "microsoft-windows-10-professional-getgenuine", |
||||||
|
"price": "12300.00", |
||||||
|
"points": "1230.00", |
||||||
|
"description": "Get Gunuine Windows Agreement GGWA \u2013 \u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u0434\u043b\u044f \u043b\u0438\u0446\u0435\u043d\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043a\u043e\u043f\u0438\u0439 \u041e\u0421 Windows, \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u043d\u044b\u0445 \u0440\u0430\u043d\u0435\u0435 \u0431\u0435\u0437 \u043b\u0438\u0446\u0435\u043d\u0437\u0438\u0438. \u0421\u0438\u0441\u0442\u0435\u043c\u0430 \u043f\u0440\u0435\u0434\u043f\u043e\u043b\u0430\u0433\u0430\u0435\u0442 \u043e\u0442 5 \u0438 \u0431\u043e\u043b\u0435\u0435 \u043b\u0438\u0446\u0435\u043d\u0437\u0438\u0439 \u0438 \u0440\u0430\u0441\u0441\u0447\u0438\u0442\u0430\u043d\u0430 \u043d\u0430 \u043a\u043e\u0440\u043f\u043e\u0440\u0430\u0442\u0438\u0432\u043d\u044b\u0445 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439.", |
||||||
|
"short_description": "", |
||||||
|
"producer": "Microsoft", |
||||||
|
"image": "products/2017/05/26/thumb_1438765887.jpg", |
||||||
|
"discount": 0, |
||||||
|
"stock": 2, |
||||||
|
"category": 6, |
||||||
|
"product_class": 5, |
||||||
|
"is_active": true, |
||||||
|
"is_hit": false, |
||||||
|
"is_new": false, |
||||||
|
"created": "2017-05-26", |
||||||
|
"updated": "2017-07-07" |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
"model": "products.product", |
||||||
|
"pk": 90, |
||||||
|
"fields": { |
||||||
|
"name": "PERFEXPERT", |
||||||
|
"slug": "perfexpert", |
||||||
|
"price": "50000.00", |
||||||
|
"points": "5000.00", |
||||||
|
"description": "\u041a\u043e\u043c\u043f\u043b\u0435\u043a\u0441\u043d\u043e\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u043c\u043e\u043d\u0438\u0442\u043e\u0440\u0438\u043d\u0433\u0430, \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044f, \u0430\u043d\u0430\u043b\u0438\u0437\u0430 \u0441\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u043a\u0438 \u0440\u0430\u0431\u043e\u0442\u044b \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0439 \u0441\u0438\u0441\u0442\u0435\u043c\u044b \u0438 \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b \u043a\u043e\u043c\u043f\u0430\u043d\u0438\u0438 \u0432 \u0440\u0435\u0436\u0438\u043c\u0435 24\u04257. \u041e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u0435\u0442 \u043e\u043f\u0435\u0440\u0430\u0442\u0438\u0432\u043d\u043e\u0435 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0432\u0441\u0435\u043c\u0438 \u0438\u043d\u0446\u0438\u0434\u0435\u043d\u0442\u0430\u043c\u0438 \u0431\u0438\u0437\u043d\u0435\u0441 \u0441\u0438\u0441\u0442\u0435\u043c\u044b \u043f\u0440\u0435\u0434\u043f\u0440\u0438\u044f\u0442\u0438\u044f, \u0438 \u0442\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0435 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0437\u0430\u0434\u0430\u0447\u0430\u043c\u0438 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438 \u0438 \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u0438 \u0440\u0430\u0431\u043e\u0442\u044b \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0439 \u0431\u0438\u0437\u043d\u0435\u0441 \u0441\u0438\u0441\u0442\u0435\u043c\u044b. PERFEXPERT \u043d\u043e\u0432\u044b\u0439 \u0443\u0440\u043e\u0432\u0435\u043d\u044c \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0430 \u043e\u0431\u0441\u043b\u0443\u0436\u0438\u0432\u0430\u043d\u0438\u044f \u0432\u0441\u0435\u0439 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0439 \u0431\u0438\u0437\u043d\u0435\u0441 \u0441\u0438\u0441\u0442\u0435\u043c\u044b.", |
||||||
|
"short_description": "", |
||||||
|
"producer": "SOFTPOINT", |
||||||
|
"image": "products/2017/05/26/thumb_1424247372.png", |
||||||
|
"discount": 0, |
||||||
|
"stock": 5, |
||||||
|
"category": 7, |
||||||
|
"product_class": 4, |
||||||
|
"is_active": true, |
||||||
|
"is_hit": false, |
||||||
|
"is_new": false, |
||||||
|
"created": "2017-05-26", |
||||||
|
"updated": "2017-07-07" |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
"model": "products.product", |
||||||
|
"pk": 91, |
||||||
|
"fields": { |
||||||
|
"name": "Office 365 Business Open", |
||||||
|
"slug": "office-365-business-open", |
||||||
|
"price": "5700.00", |
||||||
|
"points": "570.00", |
||||||
|
"description": "\u041f\u043b\u0430\u043d Office 365 \u0411\u0438\u0437\u043d\u0435\u0441 \u0432\u043a\u043b\u044e\u0447\u0430\u0435\u0442 \u0432 \u0441\u0435\u0431\u044f \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u0438 \u0438 \u0446\u0435\u043d\u043e\u0432\u044b\u0435 \u043e\u0440\u0438\u0435\u043d\u0442\u0438\u0440\u044b, \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u043e \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0430\u043d\u043d\u044b\u0435 \u0434\u043b\u044f \u0443\u0434\u043e\u0432\u043b\u0435\u0442\u0432\u043e\u0440\u0435\u043d\u0438\u044f \u043f\u043e\u0442\u0440\u0435\u0431\u043d\u043e\u0441\u0442\u0435\u0439 \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u0432 \u043c\u0430\u043b\u043e\u0433\u043e \u0438 \u0441\u0440\u0435\u0434\u043d\u0435\u0433\u043e \u0431\u0438\u0437\u043d\u0435\u0441\u0430 \u2013 \u043a\u043e\u043c\u043f\u0430\u043d\u0438\u0439 \u0440\u0430\u0437\u043c\u0435\u0440\u043e\u043c \u043e\u0442 1 \u0434\u043e 300 \u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a\u043e\u0432.", |
||||||
|
"short_description": "", |
||||||
|
"producer": "Microsoft", |
||||||
|
"image": "products/2017/05/26/office.png", |
||||||
|
"discount": 5, |
||||||
|
"stock": 13, |
||||||
|
"category": 8, |
||||||
|
"product_class": 3, |
||||||
|
"is_active": true, |
||||||
|
"is_hit": false, |
||||||
|
"is_new": false, |
||||||
|
"created": "2017-05-26", |
||||||
|
"updated": "2017-07-07" |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
"model": "products.offer", |
||||||
|
"pk": 30, |
||||||
|
"fields": { |
||||||
|
"product": 85, |
||||||
|
"name": "Kaspersky-New-One-year", |
||||||
|
"price": "1730.00", |
||||||
|
"points": "0.00", |
||||||
|
"attributes": "{\"License type\": \"New\", \"License term\": \"One year\"}" |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
"model": "products.offer", |
||||||
|
"pk": 31, |
||||||
|
"fields": { |
||||||
|
"product": 85, |
||||||
|
"name": "Kaspersky-New-One-year", |
||||||
|
"price": "2600.00", |
||||||
|
"points": "0.00", |
||||||
|
"attributes": "{\"License type\": \"New\", \"License term\": \"Two years\"}" |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
"model": "products.offer", |
||||||
|
"pk": 32, |
||||||
|
"fields": { |
||||||
|
"product": 85, |
||||||
|
"name": "Kaspersky-Prolongation-One-year", |
||||||
|
"price": "1200.00", |
||||||
|
"points": "0.00", |
||||||
|
"attributes": "{\"License type\": \"Prolongation\", \"License term\": \"One year\"}" |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
"model": "products.offer", |
||||||
|
"pk": 33, |
||||||
|
"fields": { |
||||||
|
"product": 85, |
||||||
|
"name": "Kaspersky-Migration-One-year", |
||||||
|
"price": "1900.00", |
||||||
|
"points": "0.00", |
||||||
|
"attributes": "{\"License type\": \"Migration\", \"License term\": \"One year\"}" |
||||||
|
} |
||||||
|
} |
||||||
|
] |
||||||
@ -0,0 +1,56 @@ |
|||||||
|
# from haystack.forms import FacetedSearchForm |
||||||
|
|
||||||
|
|
||||||
|
# class FacetedProductSearchForm(FacetedSearchForm): |
||||||
|
# def __init__(self, *args, **kwargs): |
||||||
|
# data = dict(kwargs.get("data", [])) |
||||||
|
# self.categories = data.get('category', []) |
||||||
|
# self.producers = data.get('producer', []) |
||||||
|
# super(FacetedProductSearchForm, self).__init__(*args, **kwargs) |
||||||
|
# |
||||||
|
# def search(self): |
||||||
|
# sqs = super(FacetedProductSearchForm, self).search() |
||||||
|
# if self.categories: |
||||||
|
# query = None |
||||||
|
# for category in self.categories: |
||||||
|
# if query: |
||||||
|
# query += u' OR ' |
||||||
|
# else: |
||||||
|
# query = u'' |
||||||
|
# query += u'"%s"' % sqs.query.clean(category) |
||||||
|
# sqs = sqs.narrow(u'category_exact:%s' % query) |
||||||
|
# if self.producers: |
||||||
|
# query = None |
||||||
|
# for producer in self.producers: |
||||||
|
# if query: |
||||||
|
# query += u' OR ' |
||||||
|
# else: |
||||||
|
# query = u'' |
||||||
|
# query += u'"%s"' % sqs.query.clean(producer) |
||||||
|
# sqs = sqs.narrow(u'brand_exact:%s' % query) |
||||||
|
# return sqs |
||||||
|
from crispy_forms.layout import Layout, ButtonHolder, Submit, HTML, Field, Button |
||||||
|
from django import forms |
||||||
|
from crispy_forms.helper import FormHelper |
||||||
|
from django.urls import reverse_lazy |
||||||
|
from django.utils.translation import ugettext_lazy as _ |
||||||
|
|
||||||
|
from .models import Product |
||||||
|
|
||||||
|
|
||||||
|
class ProductSearchForm(forms.ModelForm): |
||||||
|
field_template = 'bootstrap/forms/product_search.html' |
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs): |
||||||
|
self.helper = FormHelper() |
||||||
|
self.helper.form_action = reverse_lazy('products:search') |
||||||
|
self.helper.form_method = 'get' |
||||||
|
self.helper.layout = Layout( |
||||||
|
Field('name', template=self.field_template, placeholder="Поиск программы..."), |
||||||
|
Button(_('search'), 'search', template=self.field_template) |
||||||
|
) |
||||||
|
super().__init__(*args, **kwargs) |
||||||
|
|
||||||
|
class Meta: |
||||||
|
model = Product |
||||||
|
fields = ['name'] |
||||||
@ -0,0 +1,137 @@ |
|||||||
|
from django.db import models |
||||||
|
from django.urls import reverse_lazy |
||||||
|
from django.contrib.postgres.fields import HStoreField |
||||||
|
from django.utils.translation import ugettext_lazy as _ |
||||||
|
|
||||||
|
import mptt |
||||||
|
from mptt.models import MPTTModel, TreeForeignKey |
||||||
|
from autoslug import AutoSlugField |
||||||
|
|
||||||
|
from core.models import AbstractStatusModel, AbstractDateTimeModel |
||||||
|
|
||||||
|
|
||||||
|
class ProductAttribute(AbstractStatusModel): |
||||||
|
name = models.CharField(max_length=64, blank=True, null=True, default=None) |
||||||
|
slug = AutoSlugField(populate_from='name') |
||||||
|
main_attribute = models.BooleanField(default=False) |
||||||
|
|
||||||
|
def __str__(self): |
||||||
|
return self.name |
||||||
|
|
||||||
|
class Meta: |
||||||
|
ordering = ('slug',) |
||||||
|
verbose_name = _('Product attribute') |
||||||
|
verbose_name_plural = _('Product attributes') |
||||||
|
|
||||||
|
|
||||||
|
class ProductAttributeChoiceValue(AbstractDateTimeModel): |
||||||
|
name = models.CharField(max_length=64, blank=True, null=True, default=None) |
||||||
|
slug = AutoSlugField(populate_from='name') |
||||||
|
attribute = models.ForeignKey(ProductAttribute, on_delete=models.CASCADE, related_name='values') |
||||||
|
|
||||||
|
def __str__(self): |
||||||
|
return self.name |
||||||
|
|
||||||
|
class Meta: |
||||||
|
unique_together = ('name', 'attribute') |
||||||
|
verbose_name = 'attribute choices value' |
||||||
|
verbose_name_plural = 'attribute choices values' |
||||||
|
|
||||||
|
|
||||||
|
class Manufacturer(AbstractStatusModel): |
||||||
|
name = models.CharField(max_length=64, blank=True, null=True, default=None) |
||||||
|
slug = AutoSlugField(populate_from='name') |
||||||
|
image = models.ImageField(upload_to='producers', blank=True, verbose_name="image of producer") |
||||||
|
|
||||||
|
def __str__(self): |
||||||
|
return self.name |
||||||
|
|
||||||
|
def get_absolute_url(self): |
||||||
|
# return reverse('products:CategoriesListByProducer', args=[self.slug]) |
||||||
|
return reverse_lazy('products:manufacturer', kwargs={'producer_slug': self.slug, 'path': ''}) |
||||||
|
|
||||||
|
class Meta: |
||||||
|
verbose_name = 'Producer' |
||||||
|
verbose_name_plural = 'Producers' |
||||||
|
|
||||||
|
|
||||||
|
class ProductCategory(MPTTModel, AbstractDateTimeModel): |
||||||
|
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") |
||||||
|
|
||||||
|
def __str__(self): |
||||||
|
return self.name |
||||||
|
|
||||||
|
class Meta: |
||||||
|
verbose_name = 'Product''s category' |
||||||
|
verbose_name_plural = 'Category of products' |
||||||
|
ordering = ('tree_id', 'level') |
||||||
|
|
||||||
|
class MPTTMeta: |
||||||
|
order_insertion_by = ['name'] |
||||||
|
|
||||||
|
|
||||||
|
mptt.register(ProductCategory, order_insertion_py=['name']) |
||||||
|
|
||||||
|
|
||||||
|
class Product(AbstractStatusModel): |
||||||
|
name = models.CharField(max_length=64, db_index=True, blank=True, null=True, default=None) |
||||||
|
slug = AutoSlugField(populate_from='name') |
||||||
|
price = models.DecimalField(max_digits=10, decimal_places=2, default=0.00) |
||||||
|
description = models.TextField(db_index=True, blank=True, null=True, default=None) |
||||||
|
manufacturer = models.ForeignKey(Manufacturer, on_delete=models.PROTECT, related_name='products') |
||||||
|
image = models.ImageField(upload_to='products', blank=True, verbose_name="image of products") |
||||||
|
category = models.ForeignKey(ProductCategory, on_delete=models.SET_NULL, related_name='products', blank=True, |
||||||
|
null=True, default=None) |
||||||
|
attributes = models.ManyToManyField(ProductAttribute, related_name='categories', blank=True) |
||||||
|
discount_policy = HStoreField(blank=True, null=True, default={}) |
||||||
|
is_active = models.BooleanField(default=True) |
||||||
|
|
||||||
|
def __str__(self): |
||||||
|
return self.name |
||||||
|
|
||||||
|
def get_absolute_url(self): |
||||||
|
return reverse_lazy('products:item', args=[self.slug]) |
||||||
|
|
||||||
|
class Meta: |
||||||
|
indexes = [ |
||||||
|
models.Index(fields=['id', 'slug']) |
||||||
|
] |
||||||
|
verbose_name = _('product') |
||||||
|
verbose_name_plural = _('products') |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# def save(self, *args, **kwargs): |
||||||
|
# if self.category: |
||||||
|
# super(Product, self).save(*args, **kwargs) |
||||||
|
# |
||||||
|
# for cp in ProductClass.objects.filter(category=self.product_class): |
||||||
|
# pp = ProductProperty.objects.filter(category_property=cp, |
||||||
|
# products=self) |
||||||
|
# if not pp: |
||||||
|
# pp = ProductProperty(category_property=cp, products=self, value="--") |
||||||
|
# pp.save() |
||||||
|
|
||||||
|
# class Offer(models.Model): |
||||||
|
# name = models.CharField(max_length=64, blank=True, null=True, default=None) |
||||||
|
# slug = AutoSlugField(populate_from='name') |
||||||
|
# price = models.DecimalField(max_digits=8, decimal_places=2, null=True, default=0.00) |
||||||
|
# # points = models.DecimalField(max_digits=8, decimal_places=2, null=True, default=0.00) |
||||||
|
# products = models.ForeignKey(Product, on_delete=models.CASCADE, blank=True, null=True, default=None, |
||||||
|
# related_name='variants') |
||||||
|
# is_active = models.BooleanField(default=True) |
||||||
|
# attributes = HStoreField(blank=True, null=True, default={}) |
||||||
|
# |
||||||
|
# def __str__(self): |
||||||
|
# return self.name |
||||||
|
# |
||||||
|
# class Meta: |
||||||
|
# verbose_name = 'Offer' |
||||||
|
# verbose_name_plural = 'Offers' |
||||||
|
# |
||||||
|
# def save(self, *args, **kwargs): |
||||||
|
# self.points = self.price * decimal.Decimal('0.1') |
||||||
|
# super(Offer, self).save(*args, **kwargs) |
||||||
@ -0,0 +1,20 @@ |
|||||||
|
import datetime |
||||||
|
from haystack import indexes |
||||||
|
from .models import * |
||||||
|
|
||||||
|
class ProductIndex(indexes.SearchIndex, indexes.Indexable): |
||||||
|
text = indexes.EdgeNgramField(document=True, use_template=True, template_name="search/product_text.txt") |
||||||
|
name = indexes.EdgeNgramField(model_attr='name') |
||||||
|
description = indexes.EdgeNgramField(model_attr='description') |
||||||
|
category = indexes.CharField(model_attr='category', faceted=True) |
||||||
|
producer = indexes.CharField(model_attr='producer', faceted=True) |
||||||
|
|
||||||
|
content_auto = indexes.EdgeNgramField(model_attr='name') |
||||||
|
|
||||||
|
suggestions = indexes.FacetCharField() |
||||||
|
|
||||||
|
def get_model(self): |
||||||
|
return Product |
||||||
|
|
||||||
|
def index_queryset(self, using=None): |
||||||
|
return self.get_model().objects.all() |
||||||
@ -0,0 +1,3 @@ |
|||||||
|
from django.test import TestCase |
||||||
|
|
||||||
|
# Create your tests here. |
||||||
@ -0,0 +1,39 @@ |
|||||||
|
"""Eshop URL Configuration |
||||||
|
|
||||||
|
The `urlpatterns` list routes URLs to views. For more information please see: |
||||||
|
https://docs.djangoproject.com/en/1.10/topics/http/urls/ |
||||||
|
Examples: |
||||||
|
Function views |
||||||
|
1. Add an import: from my_app import views |
||||||
|
2. Add a URL to urlpatterns: url(r'^$', views.home, name='home') |
||||||
|
Class-based views |
||||||
|
1. Add an import: from other_app.views import Home |
||||||
|
2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home') |
||||||
|
Including another URLconf |
||||||
|
1. Import the include() function: from django.conf.urls import url, include |
||||||
|
2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls')) |
||||||
|
""" |
||||||
|
from django.urls import re_path |
||||||
|
import mptt_urls |
||||||
|
from . import views |
||||||
|
from .models import ProductCategory |
||||||
|
|
||||||
|
|
||||||
|
urlpatterns = [ |
||||||
|
re_path(r'^search/$', views.ProductSearchView.as_view(), name='search') |
||||||
|
#url(r'^products/(?P<product_id>\w+)/$', views.products, name='products'), |
||||||
|
# url(r'^$', producerslist, name='ProductList'), |
||||||
|
|
||||||
|
# Uncomment for elasticsearch |
||||||
|
|
||||||
|
# url(r'^autocomplete/$', autocomplete), |
||||||
|
# url(r'^find/$', FacetedSearchView.as_view(), name='haystack_search'), |
||||||
|
|
||||||
|
|
||||||
|
# url(r'^products/(?P<product_slug>[-\w]+)/$', products, name='Product'), |
||||||
|
# url(r'^(?P<producer_slug>[-\w]+)/(?P<path>.*)', |
||||||
|
# mptt_urls.view(model=ProductCategory, view=categorieslist, slug_field='slug'), |
||||||
|
# name='CategoriesListByProducer'), |
||||||
|
# url(r'^(?P<producer_slug>[-\w]+)/$', categorieslist, name='CategoriesListByProducer'), |
||||||
|
# url(r'^(?P<producer_slug>[-\w]+)/(?P<category_slug>[-\w]+)/$', productslist, name='ProductListByCategory') |
||||||
|
] |
||||||
@ -0,0 +1,39 @@ |
|||||||
|
from .models import Product |
||||||
|
|
||||||
|
def get_variant_picker_data(product): |
||||||
|
variants = product.variants.all() |
||||||
|
variant_attributes = product.attributes.all() |
||||||
|
data = {'variants': [], 'variantAttributes': [], 'discount_policy': product.discount_policy} |
||||||
|
|
||||||
|
for attribute in sorted(variant_attributes, key=lambda x: x.main_attribute, reverse=True): |
||||||
|
data['variantAttributes'].append({ |
||||||
|
'name': attribute.name, |
||||||
|
'public_name': attribute.name.split('_')[1], |
||||||
|
'slug': attribute.slug, |
||||||
|
'values': [{'name': value.name, 'slug': value.slug} for value in attribute.values.all()] |
||||||
|
}) |
||||||
|
|
||||||
|
for variant in variants: |
||||||
|
price = variant.price |
||||||
|
|
||||||
|
variant_data = { |
||||||
|
'id': variant.id, |
||||||
|
'slug': variant.slug, |
||||||
|
'name': variant.name, |
||||||
|
'price': int(price), |
||||||
|
'attributes': variant.attributes, |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
data['variants'].append(variant_data) |
||||||
|
|
||||||
|
return data |
||||||
|
|
||||||
|
def expand_categories(categories): |
||||||
|
products = None |
||||||
|
for e in categories: |
||||||
|
if e.name.startswith('None'): |
||||||
|
products = Product.objects.filter(category=e) |
||||||
|
return [x for x in categories if not x.name.startswith('None')], products |
||||||
|
|
||||||
|
|
||||||
@ -0,0 +1,116 @@ |
|||||||
|
from django.shortcuts import render, get_list_or_404, get_object_or_404 |
||||||
|
from django.contrib import auth |
||||||
|
from django.http import Http404 |
||||||
|
import json |
||||||
|
import decimal |
||||||
|
|
||||||
|
from django.views.generic import ListView |
||||||
|
|
||||||
|
from cart.forms import CartAddProductForm |
||||||
|
from .utils import * |
||||||
|
from cart.cart import Cart |
||||||
|
from .models import * |
||||||
|
|
||||||
|
|
||||||
|
class ProductSearchView(ListView): |
||||||
|
model = Product |
||||||
|
template_name = 'products/search.html' |
||||||
|
|
||||||
|
def get_queryset(self): |
||||||
|
queryset = super().get_queryset() |
||||||
|
return queryset.filter(name__icontains=self.request) |
||||||
|
|
||||||
|
# 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 = Producer.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 |
||||||
|
# producer = Producer.objects.get(slug=producer_slug) |
||||||
|
# if category_slug: |
||||||
|
# _categories = ProductCategory.objects.filter(is_active=True, parent=category_slug) |
||||||
|
# else: |
||||||
|
# _categories = ProductCategory.objects.filter(is_active=True, producer=producer, level__lte=0) |
||||||
|
# categories, products = expand_categories(_categories) |
||||||
|
# return render(request, 'products/categorieslist.html', {'username': username, 'categories':categories, |
||||||
|
# 'products': products}) |
||||||
|
|
||||||
|
def categorieslist(request, path, instance, producer_slug): |
||||||
|
username = auth.get_user(request).username |
||||||
|
if instance: |
||||||
|
_categories = instance.get_children() |
||||||
|
else: |
||||||
|
_categories = get_list_or_404(ProductCategory, producer__slug=producer_slug, level__lte=0) |
||||||
|
if _categories: |
||||||
|
categories, products = expand_categories(_categories) |
||||||
|
else: |
||||||
|
return productslist(request, producer_slug, instance.slug) |
||||||
|
return render( |
||||||
|
request, |
||||||
|
'products/categorieslist.html', |
||||||
|
{ |
||||||
|
'username': username, |
||||||
|
'instance': instance, |
||||||
|
'categories': categories, |
||||||
|
'producer_slug': producer_slug, |
||||||
|
'products': products |
||||||
|
} |
||||||
|
) |
||||||
|
|
||||||
|
def productslist(request, producer_slug, category_slug): |
||||||
|
username = auth.get_user(request).username |
||||||
|
category = ProductCategory.objects.get(slug=category_slug) |
||||||
|
products = Product.objects.filter(is_active=True, category=category) |
||||||
|
return render(request, 'products/productslist.html', locals()) |
||||||
|
|
||||||
|
def product(request, product_slug): |
||||||
|
username = auth.get_user(request).username |
||||||
|
product = get_object_or_404(Product, slug=product_slug, is_active=True) |
||||||
|
cart_product_form = CartAddProductForm() |
||||||
|
variant_picker_data = get_variant_picker_data(product) |
||||||
|
show_variant_picker = all([v.attributes for v in product.variants.all()]) |
||||||
|
# session_key = request.session.session_key |
||||||
|
# if not session_key: |
||||||
|
# request.session.cycle_key() |
||||||
|
|
||||||
|
return render(request, 'products/product.html', {'username': username, 'products': product, 'form': cart_product_form, |
||||||
|
'show_variant_picker': show_variant_picker, |
||||||
|
'variant_picker_data': variant_picker_data, |
||||||
|
}) |
||||||
|
|
||||||
|
# Uncomment for elasticsearch |
||||||
|
|
||||||
|
# def autocomplete(request): |
||||||
|
# sqs = SearchQuerySet().autocomplete(content_auto=request.GET.get('query', ''))[:5] |
||||||
|
# s = [] |
||||||
|
# for result in sqs: |
||||||
|
# print(result) |
||||||
|
# d = {"value": result.name, "data": result.object.slug} |
||||||
|
# s.append(d) |
||||||
|
# output = {'suggestions': s} |
||||||
|
# return JsonResponse(output) |
||||||
|
# |
||||||
|
# class FacetedSearchView(BaseFacetedSearchView): |
||||||
|
# form_class = FacetedProductSearchForm |
||||||
|
# facet_fields = ['category', 'producer'] |
||||||
|
# template_name = 'search/search.html' |
||||||
|
# paginate_by = 3 |
||||||
|
# context_object_name = 'object_list' |
||||||
Loading…
Reference in new issue