Introduce VariationDict to reduce duplicate code

This commit is contained in:
Raphael Michel
2014-10-07 10:25:29 +02:00
parent 421b4d8eca
commit 1ec224049d
6 changed files with 90 additions and 25 deletions

View File

@@ -7,6 +7,8 @@ from django.utils.translation import ugettext_lazy as _
from django.template.defaultfilters import date as _date
from django.core.validators import RegexValidator
from tixlbase.types import VariationDict
class UserManager(BaseUserManager):
"""
@@ -571,10 +573,13 @@ class Item(models.Model):
def get_all_variations(self):
"""
This method returns a list containing all variations of this
item. The list contains one dictionary per variation, where
item. The list contains one VariationDict per variation, where
the Proprty IDs are keys and the PropertyValue objects are
values. If an ItemVariation object exists, it is available in
the dictionary via the special key 'variation'.
VariationDicts differ from dicts only by specifying some extra
methods.
"""
all_variations = self.variations.all().prefetch_related("values")
all_properties = self.properties.all().prefetch_related("values")
@@ -583,20 +588,20 @@ class Item(models.Model):
key = []
for v in var.values.all():
key.append((v.prop_id, v.pk))
key = hash(tuple(sorted(key)))
key = tuple(sorted(key))
variations_cache[key] = var
result = []
for comb in product(*[prop.values.all() for prop in all_properties]):
if len(comb) == 0:
result.append({})
result.append(VariationDict())
continue
key = []
var = {}
var = VariationDict()
for v in comb:
key.append((v.prop.pk, v.pk))
var[v.prop.pk] = v
key = hash(tuple(sorted(key)))
key = tuple(sorted(key))
if key in variations_cache:
var['variation'] = variations_cache[key]
result.append(var)

View File

@@ -5,6 +5,7 @@ from tixlbase.models import (
Event, Organizer, Item, ItemVariation,
Property, PropertyValue
)
from tixlbase.types import VariationDict
class ItemVariationsTest(TestCase):
@@ -44,7 +45,7 @@ class ItemVariationsTest(TestCase):
self.assertEqual(len(v), 3)
values = []
for var in v:
self.assertIs(type(var), dict)
self.assertIs(type(var), VariationDict)
self.assertIn(p.pk, var)
self.assertIs(type(var[p.pk]), PropertyValue)
values.append(var[p.pk].value)
@@ -59,7 +60,7 @@ class ItemVariationsTest(TestCase):
values = []
num_variations = 0
for var in v:
self.assertIs(type(var), dict)
self.assertIs(type(var), VariationDict)
if 'variation' in var and type(var['variation']) is ItemVariation:
self.assertEqual(iv.pk, var['variation'].pk)
values.append(var['variation'].values.all()[0].value)
@@ -80,7 +81,7 @@ class ItemVariationsTest(TestCase):
values = []
num_variations = 0
for var in v:
self.assertIs(type(var), dict)
self.assertIs(type(var), VariationDict)
if 'variation' in var:
self.assertEqual(iv.pk, var['variation'].pk)
values.append(sorted([ivv.value for ivv in iv.values.all()]))

71
src/tixlbase/types.py Normal file
View File

@@ -0,0 +1,71 @@
class VariationDict(dict):
"""
A VariationDict object behaves exactle the same as the Python built-in
``dict`` does, but adds some special methods. It is used for the dicts
returned by ``Item.get_all_variations()`` to avoid duplicate code in the
code calling this method.
"""
def relevant_items(self):
"""
Iterate over all items with numeric keys.
This is in use because the variation dictionaries use property ids
as key and have some special keys like 'variation'.
"""
for i in self.items():
if type(i[0]) is int:
yield i
def relevant_values(self):
"""
Iterate over all values with numeric keys.
This is in use because the variation dictionaries use property ids
as key and have some special keys like 'variation'.
"""
for i in self.items():
if type(i[0]) is int:
yield i[1]
def identify(self):
"""
Build an identifier for this dict. This can be any string used to
compare one VariationDict to others.
In the current implementation, it is a string containing a list of
the PropertyValue id's, sorted by the Property id's and is therefore
unique among one item.
"""
order_key = lambda i: i[0]
return ",".join([
str(v[1].pk) for v in sorted(self.relevant_items(), key=order_key)
])
def __eq__(self, other):
if type(other) is type(self):
return self.identify() == other.identify()
else:
return super().__eq__(other)
def ordered_values(self):
"""
Returns a list of values ordered by their keys
"""
return [
i[1] for i
in sorted(
[it for it in self.relevant_items()],
key=lambda i: i[0]
)
]
def copy(self):
"""
Return a one-level deep copy of this object (create a new
VariationDict but make a shallow copy of the dict inside it).
"""
new = VariationDict()
for k, v in self.items():
new[k] = v
return new