From 7c7201bcecbb5b557240d588e88d7befcffb6a8a Mon Sep 17 00:00:00 2001 From: Artemiy Rodionov Date: Thu, 16 May 2019 18:35:25 +0300 Subject: [PATCH 1/5] Fix product price filter for admin panel --- docker/Makefile | 3 +++ shopelectro/admin.py | 16 +++++++++++++--- shopelectro/tests/tests_selenium_admin.py | 5 ----- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/docker/Makefile b/docker/Makefile index 3ce708a5..0a1c665a 100644 --- a/docker/Makefile +++ b/docker/Makefile @@ -13,6 +13,9 @@ generate-production-static-data deploy # ---------------------- Dev section ---------------------- +shell: + $(dc) run --rm app python manage.py shell + migrate: $(dc) run --rm app python manage.py migrate diff --git a/shopelectro/admin.py b/shopelectro/admin.py index bdae28c1..4cf832a7 100644 --- a/shopelectro/admin.py +++ b/shopelectro/admin.py @@ -12,7 +12,7 @@ from ecommerce import mailer from ecommerce.models import Position from pages.models import CustomPage, FlatPage, PageTemplate -from generic_admin import inlines, mixins, models, sites +from generic_admin import inlines, mixins, models, sites, filters from shopelectro import models as se_models from shopelectro.views.admin import TableEditor @@ -34,6 +34,11 @@ def prepare_has_filter_queryset(value, db_table, queryset): return queryset.filter(**{query: value != 'yes'}) +class ProductPriceFilter(filter.PriceRange): + + price_lookup = 'shopelectro_product__price' + + class HasTagsFilter(admin.SimpleListFilter): product_model = se_models.Product @@ -155,7 +160,12 @@ class ProductPageAdmin(models.ProductPageAdmin): add = False delete = False category_page_model = se_models.CategoryPage - list_filter = [*models.ProductPageAdmin.list_filter, HasTagsFilter, HasCategoryFilter] + list_filter = [ + *models.ProductPageAdmin.list_filter, + ProductPriceFilter, + HasTagsFilter, + HasCategoryFilter, + ] inlines = [ProductInline, inlines.ImageInline] search_fields = [ 'shopelectro_product__vendor_code', 'name', 'slug', @@ -169,7 +179,7 @@ def model_id(self, obj): def get_queryset(self, request): return ( - super(ProductPageAdmin, self) + super() .get_queryset(request) .select_related('shopelectro_product') ) diff --git a/shopelectro/tests/tests_selenium_admin.py b/shopelectro/tests/tests_selenium_admin.py index 0463b19e..ea80221d 100644 --- a/shopelectro/tests/tests_selenium_admin.py +++ b/shopelectro/tests/tests_selenium_admin.py @@ -143,11 +143,6 @@ def test_login(self): admin_title = self.browser.find_element_by_id('site-name') self.assertIn(self.title_text, admin_title.text) - # @todo #822:30m Resurrect admin price filter. - # It's failing after fix changing `PriceRange.price_lookup` value. - # Fix was here: https://github.com/fidals/refarm-site/pull/325 - # Just disable this filter for STB. It's not relevant there - @unittest.expectedFailure def test_product_price_filter(self): """ Price filter is able to filter products by set range. From b0ee1c75bd05ba697ccc08e67614dd2796d21581 Mon Sep 17 00:00:00 2001 From: Artemiy Rodionov Date: Thu, 16 May 2019 20:26:47 +0300 Subject: [PATCH 2/5] Create few receipts for Makefile --- docker/Makefile | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/docker/Makefile b/docker/Makefile index 0a1c665a..d726617c 100644 --- a/docker/Makefile +++ b/docker/Makefile @@ -13,8 +13,11 @@ generate-production-static-data deploy # ---------------------- Dev section ---------------------- -shell: - $(dc) run --rm app python manage.py shell +repl: + $(dc) exec app python manage.py shell + +bash: + $(dc) exec app bash migrate: $(dc) run --rm app python manage.py migrate From 571b375c783d5d9cd8e3f788fd930ac8123b8e4c Mon Sep 17 00:00:00 2001 From: Artemiy Rodionov Date: Thu, 16 May 2019 20:27:09 +0300 Subject: [PATCH 3/5] Fix typo in ProductPriceFilter --- requirements.txt | 2 +- shopelectro/admin.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index e4f40fbf..d273a63b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -25,4 +25,4 @@ sorl-thumbnail==12.5.0 python-telegram-bot==11.1.0 sentry-sdk==0.7.2 https://github.com/selwin/django-user_agents/archive/master.zip -https://github.com/fidals/refarm-site/archive/0.5.11.zip +https://github.com/fidals/refarm-site/archive/0.5.12.zip diff --git a/shopelectro/admin.py b/shopelectro/admin.py index 4cf832a7..a40b2182 100644 --- a/shopelectro/admin.py +++ b/shopelectro/admin.py @@ -34,7 +34,7 @@ def prepare_has_filter_queryset(value, db_table, queryset): return queryset.filter(**{query: value != 'yes'}) -class ProductPriceFilter(filter.PriceRange): +class ProductPriceFilter(filters.PriceRange): price_lookup = 'shopelectro_product__price' From b5bff70e4735b8d2413126dbcd2ef080b57ebd04 Mon Sep 17 00:00:00 2001 From: Artemiy Rodionov Date: Thu, 16 May 2019 21:17:08 +0300 Subject: [PATCH 4/5] Add price field to AdminProductPage --- shopelectro/admin.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/shopelectro/admin.py b/shopelectro/admin.py index a40b2182..301ffbe5 100644 --- a/shopelectro/admin.py +++ b/shopelectro/admin.py @@ -166,6 +166,7 @@ class ProductPageAdmin(models.ProductPageAdmin): HasTagsFilter, HasCategoryFilter, ] + list_display = ['model_id', 'name', 'custom_parent', 'price', 'links', 'is_active'] inlines = [ProductInline, inlines.ImageInline] search_fields = [ 'shopelectro_product__vendor_code', 'name', 'slug', @@ -177,10 +178,16 @@ def model_id(self, obj): model_id.short_description = _('Vendor code') model_id.admin_order_field = 'shopelectro_product__vendor_code' + def price(self, obj): + return obj.model.price + + price.short_description = _('Price') + price.admin_order_field = '_product_price' + def get_queryset(self, request): + qs = super().get_queryset(request) return ( - super() - .get_queryset(request) + self.add_reference_to_field_on_related_model(qs, _product_price='price') .select_related('shopelectro_product') ) From a95a0de6a5b083647ef4676d118609474665fd1a Mon Sep 17 00:00:00 2001 From: Artemiy Rodionov Date: Fri, 17 May 2019 17:13:22 +0300 Subject: [PATCH 5/5] Fix related tests --- shopelectro/tests/tests_selenium_admin.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/shopelectro/tests/tests_selenium_admin.py b/shopelectro/tests/tests_selenium_admin.py index ea80221d..0e7b07b6 100644 --- a/shopelectro/tests/tests_selenium_admin.py +++ b/shopelectro/tests/tests_selenium_admin.py @@ -59,6 +59,10 @@ def setUp(self): class AdminPage(AdminSeleniumTestCase): """Selenium-based tests for Admin page UI.""" + # @todo #835:60m Fix admin filter tests + # Tests rely upon order of html markup. + # It is fragile and always breaks after admin filter modifications. + @classmethod def setUpClass(cls): super().setUpClass() @@ -67,11 +71,11 @@ def setUpClass(cls): cls.title_text = 'Shopelectro administration' cls.active_products = '//*[@id="changelist-filter"]/ul[1]/li[2]/a' cls.inactive_products = '//*[@id="changelist-filter"]/ul[1]/li[3]/a' - cls.price_filter = '//*[@id="changelist-filter"]/ul[2]/li[3]/a' - cls.filter_by_has_content = '//*[@id="changelist-filter"]/ul[3]/li[2]/a' - cls.filter_by_has_not_content = '//*[@id="changelist-filter"]/ul[3]/li[3]/a' - cls.filter_by_has_image = '//*[@id="changelist-filter"]/ul[4]/li[2]/a' - cls.filter_by_has_not_image = '//*[@id="changelist-filter"]/ul[4]/li[3]/a' + cls.price_filter = '//*[@id="changelist-filter"]/ul[4]/li[3]/a' + cls.filter_by_has_content = '//*[@id="changelist-filter"]/ul[2]/li[2]/a' + cls.filter_by_has_not_content = '//*[@id="changelist-filter"]/ul[2]/li[3]/a' + cls.filter_by_has_image = '//*[@id="changelist-filter"]/ul[3]/li[2]/a' + cls.filter_by_has_not_image = '//*[@id="changelist-filter"]/ul[3]/li[3]/a' cls.is_active_img = 'field-is_active' cls.autocomplete_text = 'Prod' cls.jstree_children = 'jstree-children' @@ -159,7 +163,7 @@ def test_product_price_filter(self): )) product_price = int(float(product.text.replace(',', '.'))) - self.assertTrue(product_price >= 1000) + self.assertTrue(product_price >= 1000 and product_price < 2000) def test_image_filter(self): """Image filter is able to filter pages by the presence of the image."""