Skip to content

Commit

Permalink
#880 Create CatalogBlock model (#925)
Browse files Browse the repository at this point in the history
* Create CatalogBlock model and add sublime's configs to .gitignore

* Remove related todo

* Review fixes

* Rework MatrixBlock tests
  • Loading branch information
ArtemijRodionov committed Jul 4, 2019
1 parent 5dc52ea commit 6ed0777
Show file tree
Hide file tree
Showing 4 changed files with 159 additions and 4 deletions.
28 changes: 28 additions & 0 deletions shopelectro/migrations/0036_matrixblock.py
@@ -0,0 +1,28 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.20 on 2019-07-04 08:46
from __future__ import unicode_literals

from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

dependencies = [
('shopelectro', '0035_product_in_pack'),
]

operations = [
migrations.CreateModel(
name='MatrixBlock',
fields=[
('category', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, primary_key=True, related_name='matrix_block', serialize=False, to='shopelectro.Category', verbose_name='category')),
('block_size', models.PositiveSmallIntegerField(null=True, verbose_name='block size')),
],
options={
'verbose_name': 'Matrix block',
'verbose_name_plural': 'Matrix blocks',
'ordering': ['category__page__position', 'category__name'],
},
),
]
57 changes: 57 additions & 0 deletions shopelectro/models.py
Expand Up @@ -56,6 +56,63 @@ def get_absolute_url(self):
return reverse('category', args=(self.page.slug,))


class MatrixBlockManager(models.Manager):

def blocks(self):
return (
super()
.get_queryset()
.select_related('category', 'category__page')
.prefetch_related('category__children')
.filter(category__level=0, category__page__is_active=True)
)


class MatrixBlock(models.Model):
"""It is an UI element of catalog matrix."""

# @todo #880:30m Add MatrixBlock to the admin panel.
# Inline it on Category Edit page.

# @todo #880:60m Use MatrixBlock in the matrix view.
# Get the block_size data from the matrix view and fill out the model.

class Meta:
verbose_name = _('Matrix block')
verbose_name_plural = _('Matrix blocks')
ordering = ['category__page__position', 'category__name']

objects = MatrixBlockManager()

category = models.OneToOneField(
Category,
on_delete=models.CASCADE,
primary_key=True,
verbose_name=_('category'),
related_name=_('matrix_block'),
limit_choices_to={'level': 0},
)

block_size = models.PositiveSmallIntegerField(
null=True,
verbose_name=_('block size'),
)

@property
def name(self):
self.category.name

@property
def url(self):
self.category.url

def rows(self) -> SECategoryQuerySet:
rows = self.category.children.active()
if self.block_size:
return rows[:self.block_size]
return rows


class Product(
catalog_models.AbstractProduct,
catalog_models.AbstractPosition,
Expand Down
75 changes: 74 additions & 1 deletion shopelectro/tests/tests_models.py
Expand Up @@ -2,10 +2,11 @@
from itertools import chain

from django.conf import settings
from django.db.utils import IntegrityError
from django.forms.models import model_to_dict
from django.test import TestCase, TransactionTestCase, tag

from shopelectro.models import Product, Tag, TagGroup
from shopelectro.models import Category, MatrixBlock, Product, Tag, TagGroup


@tag('fast')
Expand Down Expand Up @@ -86,3 +87,75 @@ def test_get_brands_from_products(self):
p: p.tags.filter(group__name=settings.BRAND_TAG_GROUP_NAME).first()
for p in products
}

def test_get_matrix_blocks(self):
roots = Category.objects.filter(level=0)
roots_count = roots.count()
for category in roots:
MatrixBlock.objects.create(category=category)

blocks = MatrixBlock.objects.blocks()

# 2 queries: MatrixBlock + Category joined with CategoryPage
# select_related doesn't deffer the queries
with self.assertNumQueries(2):
self.assertEquals(roots_count, len(blocks))
for block in blocks:
self.assertTrue(block.category)
self.assertTrue(block.category.page)

with self.assertNumQueries(2):
for block in blocks:
self.assertTrue(block.rows())


@tag('fast')
class MatrixBlockModel(TestCase):

fixtures = ['dump.json']

def test_block_category_relation_uniqueness(self):
category = Category.objects.first()

with self.assertRaises(IntegrityError):
MatrixBlock.objects.create(category=category)
MatrixBlock.objects.create(category=category)

def test_unsized_rows_count(self):
block = MatrixBlock.objects.create(category=Category.objects.first())

self.assertEquals(
block.category.children.active().count(),
block.rows().count(),
)

def test_sized_rows_count(self):
sized_category, oversized_category = Category.objects.all()[:2]

# block_size < category's children quantity
sized_block = MatrixBlock.objects.create(
category=sized_category,
block_size=sized_category.children.count() - 1,
)
self.assertNotEquals(
sized_category.children.active().count(),
sized_block.rows().count(),
)
self.assertEquals(
sized_block.block_size,
sized_block.rows().count(),
)

# block_size > category's children quantity
oversized_block = MatrixBlock.objects.create(
category=oversized_category,
block_size=oversized_category.children.count() + 1,
)
self.assertEquals(
oversized_category.children.active().count(),
oversized_block.rows().count(),
)
self.assertNotEquals(
oversized_block.block_size,
oversized_block.rows().count(),
)
3 changes: 0 additions & 3 deletions shopelectro/views/catalog.py
Expand Up @@ -42,9 +42,6 @@ def category_matrix(request, page: str):
# How the matrix looks like:
# https://github.com/fidals/shopelectro/issues/837#issuecomment-501161967

# @todo #837:60m Improve categories matrix arch.
# Now it's untyped data structure with common comments.
# Turn it to the set of object with clear names.
matrix[(root.name, root.url)] = (
children
if i not in MATRIX_BLOCKS_TO_LIMIT
Expand Down

3 comments on commit 6ed0777

@0pdd
Copy link
Collaborator

@0pdd 0pdd commented on 6ed0777 Jul 4, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Puzzle 837-edb24a44 disappeared from shopelectro/views/catalog.py, that's why I closed #880. Please, remember that the puzzle was not necessarily removed in this particular commit. Maybe it happened earlier, but we discovered this fact only now.

@0pdd
Copy link
Collaborator

@0pdd 0pdd commented on 6ed0777 Jul 4, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Puzzle 880-c9d8b5dc discovered in shopelectro/models.py and submitted as #934. Please, remember that the puzzle was not necessarily added in this particular commit. Maybe it was added earlier, but we discovered it only now.

@0pdd
Copy link
Collaborator

@0pdd 0pdd commented on 6ed0777 Jul 4, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Puzzle 880-51a8e904 discovered in shopelectro/models.py and submitted as #935. Please, remember that the puzzle was not necessarily added in this particular commit. Maybe it was added earlier, but we discovered it only now.

Please sign in to comment.