Package: django-eventtools
django-eventtools is a lightweight library designed to handle repeating
and one-off event occurrences for display on a website.Circle
CIcodecovLatest VersionInstallationDownload the source fromhttps://pypi.python.org/pypi/django-eventtools/and runpython setup.py install, or:> pip install django-eventtoolsDjango 1.8 or higher is required.SetupGiven the following models:fromdjango.dbimportmodelsfromeventtools.modelsimportBaseEvent,BaseOccurrenceclassMyEvent(BaseEvent):title=models.CharField(max_length=100)classMyOccurrence(BaseOccurrence):event=models.ForeignKey(MyEvent)UsageCreate a sample event & occurrences>>> from datetime import datetime
>>> from myapp.models import MyEvent
>>> event = MyEvent.objects.create(title='Test event')
>>> once_off = MyOccurrence.objects.create(
        event=event,
        start=datetime(2016, 1, 1, 12, 0),
        end=datetime(2016, 1, 1, 2, 0))
>>> christmas = MyOccurrence.objects.create(
        event=event,
        start=datetime(2015, 12, 25, 7, 0),
        end=datetime(2015, 12, 25, 22, 0),
        repeat='RRULE:FREQ=YEARLY')
>>> daily = MyOccurrence.objects.create(
        event=event,
        start=datetime(2016, 1, 1, 7, 0),
        end=datetime(2016, 1, 1, 8, 0),
        repeat='RRULE:FREQ=DAILY')Event and Occurrence instances, and their associated querysets, all
support theall_occurrencesmethod, which takes two optional
arguments -from_dateandto_date, which may be dates or
datetimes.from_dateandto_datedefault toNone. The method
returns a python generator yielding tuples in the format(start, end, instance)- for example:>>> MyEvent.objects.all().all_occurrences()
>>> event.all_occurrences(from_date=datetime(2015, 1, 1, 10, 0))
>>> event.occurrence_set.all().all_occurrences(to_date=date(2016, 1, 1))
>>> occurrence.all_occurrences(from_date=date(2016, 1, 1),
                               to_date=date(2016, 12, 31))instanceis an instance of the corresponding BaseOccurrence
subclass.Anext_occurrencemethod is also provided, taking the same
arguments, but returning a single occurrence tuple.>>> event.next_occurrence()
>>> event.next_occurrence(from_date=date(2016, 1, 1))The methodfirst_occurrencealso returns a single occurrence tuple,
but takes no arguments.Queryset filteringEvent and Occurrence querysets can be filtered, but due to uncertainty
with repetitions,from_datefiltering is only an approximation
(whereasto_datefiltering is accurate). If you need a queryset
filtered exactly, passexact=True- this will filter using generated
occurrences but still return a queryset - but be careful with this as it
may be very slow and/or CPU-hungry. For example>>> MyEvent.objects.for_period(from_date=date(2015, 1, 1),
                             to_date=date(2015, 12, 31))
>>> event.occurrence_set.for_period(from_date=date(2015, 1, 1), exact=True)Sorting querysetsEvent and Occurrence querysets can also be sorted by their next
occurrence using thesort_by_nextmethod. By default this sorts
instances by their first occurrence; the optionalfrom_dateargument
will sort by the next occurrence afterfrom_date. For example>>> MyEvent.objects.all().sort_by_next()
>>> event.occurrence_set.for_period(from_date=date(2015, 1, 1)) \
>>>      .sort_by_next(date(2015, 1, 1))Note that this method returns a sorted list, not a queryset.Custom repeat intervalsOccurrences can repeat using any interval that can be expressed as anrrulestr.
To customise the available options, setEVENTTOOLS_REPEAT_CHOICESin
your django settings. The default value isEVENTTOOLS_REPEAT_CHOICES=(("RRULE:FREQ=DAILY",'Daily'),("RRULE:FREQ=WEEKLY",'Weekly'),("RRULE:FREQ=MONTHLY",'Monthly'),("RRULE:FREQ=YEARLY",'Yearly'),)SetEVENTTOOLS_REPEAT_CHOICES = Noneto make repeat a plain-text
field.Occurrence cancellations or modificationsCancelling or modifying a single occurrence repetition is not currently
supported, but can be implemented by overriding a couple of methods. For
example, the following allows cancellations or one-off modifications to
the start time of a repetition:fromeventtools.modelsimport(BaseEvent,BaseOccurrence,default_naive)fromdjango.dbimportmodelsclassMyEvent(BaseEvent):passclassMyEventOccurrence(BaseOccurrence):event=models.ForeignKey(MyEvent)overrides=models.ManyToManyField('MyEventOccurrenceOverride',blank=True)defget_repeater(self):rule=super().get_repeater()# gets rruleset from parent methodruleset.rrule(rule)foroverrideinself.overrides.all():ruleset.exdate(default_naive(override.start))# remove occurrenceifoverride.modified_start:# reschedule occurrence if definedruleset.rdate(default_naive(override.modified_start))returnrulesetclassMyEventOccurrenceOverride(models.Model):start=models.DateTimeField()# must match targeted repetition exactly# new start, leave blank to cancelmodified_start=models.DateTimeField(blank=True,null=True)Note that start times must match exactly, so if the MyEventOccurrence
start is changed, any previously-matching overrides will no longer be
applied.Running testsUse tox (https://pypi.python.org/pypi/tox):> pip install tox
> cd path-to/django-eventtools
> tox