mirror of
https://github.com/pretix/pretix.git
synced 2026-04-28 00:02:37 +00:00
Introduce VariationDict to reduce duplicate code
This commit is contained in:
@@ -68,6 +68,8 @@ It is sent out with several arguments:
|
||||
the item does not have any properties, the list will contain exactly one empty
|
||||
dictionary. Please not: this is *not* the list of all possible variations, this is
|
||||
only the list of all variations the frontend likes to determine the status for.
|
||||
Technically, you won't get ``dict`` objects but ``tixlbase.types.VariationDict``
|
||||
objects, which behave exactly the same but add some extra methods.
|
||||
context
|
||||
A yet-to-defined context object containing information about the user and the order
|
||||
process. This is required to implement coupon-systems or similar restrictions.
|
||||
@@ -158,9 +160,7 @@ In our example, the implementation could look like this::
|
||||
# Make up some unique key for this variation
|
||||
cachekey = 'timerestriction:%d:%s' % (
|
||||
item.pk,
|
||||
",".join(sorted(
|
||||
[str(v[1].pk) for v in v.items() if v[0] != 'variation']
|
||||
))
|
||||
v.identify(),
|
||||
)
|
||||
|
||||
# Fetch from cache, if available
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
71
src/tixlbase/types.py
Normal 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
|
||||
@@ -561,16 +561,6 @@ class ItemVariations(TemplateView, SingleObjectMixin):
|
||||
if v.prop.pk != prop2.pk
|
||||
]
|
||||
|
||||
# Given an dictionary like the ones returned by
|
||||
# Item.get_all_variation() this will return a list of PropertyValue
|
||||
# objects sorted by the primary keys of the properties they belong
|
||||
# to.
|
||||
values = lambda variation: [
|
||||
i[1] for i in sorted(
|
||||
[it for it in variation.items() if it[0] != 'variation']
|
||||
)
|
||||
]
|
||||
|
||||
# Given a list of variations, this will sort them by their position
|
||||
# on the x-axis
|
||||
sort = lambda v: v[prop2.pk].pk
|
||||
@@ -592,7 +582,7 @@ class ItemVariations(TemplateView, SingleObjectMixin):
|
||||
selection = selector(gridrow + (val1,))
|
||||
# We now iterate over all variations who generate the same
|
||||
# selector as 'selection'.
|
||||
filtered = [v for v in variations if selector(values(v)) == selection]
|
||||
filtered = [v for v in variations if selector(v.relevant_values()) == selection]
|
||||
for variation in sorted(filtered, key=sort):
|
||||
form = self.get_form(variation, data)
|
||||
formrow.append(form)
|
||||
|
||||
@@ -59,9 +59,7 @@ def availability_handler(sender, **kwargs):
|
||||
# Make up some unique key for this variation
|
||||
cachekey = 'timerestriction:%d:%s' % (
|
||||
item.pk,
|
||||
",".join(sorted(
|
||||
[str(v[1].pk) for v in v.items() if v[0] != 'variation']
|
||||
))
|
||||
v.identify(),
|
||||
)
|
||||
|
||||
# Fetch from cache, if available
|
||||
|
||||
Reference in New Issue
Block a user