Improve documentation, add missing migrations

This commit is contained in:
Raphael Michel
2014-10-07 00:46:47 +02:00
parent a64d00aa82
commit b0126e30f3
5 changed files with 179 additions and 6 deletions

View File

@@ -97,9 +97,119 @@ dictionary can be extended by the following two keys:
In our example, the implementation could look like this:: In our example, the implementation could look like this::
TBD from django.dispatch import receiver
from django.utils.timezone import now
from tixlbase.signals import determine_availability
from .models import TimeRestriction
@receiver(determine_availability)
def availability_handler(sender, **kwargs):
# Handle the signal's input arguments
item = kwargs['item']
variations = kwargs['variations']
cache = kwargs['cache']
context = kwargs['context'] # NOQA
# Fetch all restriction objects applied to this item
restrictions = list(TimeRestriction.objects.filter(
items__in=(item,),
).prefetch_related('variations'))
# If we do not know anything about this item, we are done here.
if len(restrictions) == 0:
return variations
# IMPORTANT:
# We need to make a two-level deep copy of the variations list before we
# modify it, becuase we need to to copy the dictionaries. Otherwise, we'll
# interfere with other plugins.
variations = [d.copy() for d in variations]
# The maximum validity of our cached values is the next date, one of our
# timeframe_from or tiemframe_to actions happens
def timediff(restrictions):
for r in restrictions:
if r.timeframe_from >= now():
yield (r.timeframe_from - now()).total_seconds()
if r.timeframe_to >= now():
yield (r.timeframe_to - now()).total_seconds()
try:
cache_validity = min(timediff(restrictions))
except ValueError:
# empty sequence
# If we get here, there are restrictions available but nothing will
# change about them any more. If it were not for the case of no
# restriction for the base item but restrictions for special
# variations, we could quit here with 'item not available'.
cache_validity = 3600
# Walk through all variations we are asked for
for v in variations:
# If this point is reached, there ARE time restrictions for this item
# Therefore, it is only available inside one of the timeframes, but not
# without any timeframe
available = False
price = None
# 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']
))
)
# Fetch from cache, if available
cached = cache.get(cachekey)
if cached is not None:
v['available'] = (cached.split(":")[0] == 'True')
try:
v['price'] = float(cached.split(":")[1])
except ValueError:
v['price'] = None
continue
# Walk through all restriction objects applied to this item
for restriction in restrictions:
applied_to = list(restriction.variations.all())
# Only take this restriction into consideration if it either
# is directly applied to this variation OR is applied to all
# variations (e.g. the applied_to list is empty)
if len(applied_to) > 0:
if 'variation' not in v or v['variation'] not in applied_to:
continue
if (restriction.timeframe_from <= now()
and restriction.timeframe_to >= now()):
# Selling this item is currently possible
available = True
# If multiple time frames are currently active, make sure to
# get the cheapest price:
if (restriction.price is not None
and (price is None or restriction.price < price)):
price = restriction.price
v['available'] = available
v['price'] = price
cache.set(
cachekey,
'%s:%s' % (
'True' if available else 'False',
str(price) if price else ''
),
cache_validity
)
return variations
.. IMPORTANT:: .. IMPORTANT::
Please note the copying of the ``variations`` list in the example above. Please note the copying of the ``variations`` list in the example above (line 30).
If you do not copy down to the ``dict`` objects, you will run into
interference problems with other plugins.
.. _caching feature: https://docs.djangoproject.com/en/1.7/topics/cache/ .. _caching feature: https://docs.djangoproject.com/en/1.7/topics/cache/

View File

@@ -0,0 +1,24 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('tixlbase', '0014_auto_20141005_1037'),
]
operations = [
migrations.AlterField(
model_name='item',
name='questions',
field=models.ManyToManyField(blank=True, related_name='items', verbose_name='Questions', help_text='The user will be asked to fill in answers for the selected questions', to='tixlbase.Question'),
),
migrations.AlterField(
model_name='question',
name='event',
field=models.ForeignKey(to='tixlbase.Event', related_name='questions'),
),
]

View File

@@ -0,0 +1,32 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('tixlbase', '0015_auto_20141006_2205'),
]
operations = [
migrations.CreateModel(
name='TimeRestriction',
fields=[
('id', models.AutoField(primary_key=True, serialize=False, verbose_name='ID', auto_created=True)),
('timeframe_from', models.DateTimeField(verbose_name='Start of time frame')),
('timeframe_to', models.DateTimeField(verbose_name='End of time frame')),
('price', models.DecimalField(max_digits=7, verbose_name='Price in time frame', decimal_places=2, null=True, blank=True)),
('event', models.ForeignKey(related_name='restrictions_timerestriction_timerestriction', to='tixlbase.Event', verbose_name='Event')),
('items', models.ManyToManyField(to='tixlbase.Item', related_name='restrictions_timerestriction_timerestriction')),
('variations', models.ManyToManyField(to='tixlbase.ItemVariation', related_name='restrictions_timerestriction_timerestriction')),
],
options={
'abstract': False,
'verbose_name_plural': 'Restrictions',
'verbose_name': 'Restriction',
},
bases=(models.Model,),
),
]

View File

@@ -59,7 +59,9 @@ def availability_handler(sender, **kwargs):
# Make up some unique key for this variation # Make up some unique key for this variation
cachekey = 'timerestriction:%d:%s' % ( cachekey = 'timerestriction:%d:%s' % (
item.pk, item.pk,
",".join(sorted([str(v[1].pk) for v in v.items() if v[0] != 'variation'])) ",".join(sorted(
[str(v[1].pk) for v in v.items() if v[0] != 'variation']
))
) )
# Fetch from cache, if available # Fetch from cache, if available
@@ -83,19 +85,24 @@ def availability_handler(sender, **kwargs):
if 'variation' not in v or v['variation'] not in applied_to: if 'variation' not in v or v['variation'] not in applied_to:
continue continue
if restriction.timeframe_from <= now() and restriction.timeframe_to >= now(): if (restriction.timeframe_from <= now()
and restriction.timeframe_to >= now()):
# Selling this item is currently possible # Selling this item is currently possible
available = True available = True
# If multiple time frames are currently active, make sure to # If multiple time frames are currently active, make sure to
# get the cheapest price: # get the cheapest price:
if restriction.price is not None and (price is None or restriction.price < price): if (restriction.price is not None
and (price is None or restriction.price < price)):
price = restriction.price price = restriction.price
v['available'] = available v['available'] = available
v['price'] = price v['price'] = price
cache.set( cache.set(
cachekey, cachekey,
'%s:%s' % ('True' if available else 'False', str(price) if price else ''), '%s:%s' % (
'True' if available else 'False',
str(price) if price else ''
),
cache_validity cache_validity
) )