{"id":8111,"library":"django-recurrence","title":"Django Recurrence","description":"django-recurrence is a utility for working with recurring dates in Django. It provides `Recurrence/Rule` objects based on a subset of rfc2445 (wrapping `dateutil.rrule`), a `RecurrenceField` for database storage, and a JavaScript widget for user input. The library is currently at version 1.14 and is actively maintained by the Jazzband community, with regular releases to support new Django and Python versions.","status":"active","version":"1.14","language":"en","source_language":"en","source_url":"https://github.com/jazzband/django-recurrence","tags":["django","recurrence","scheduling","dates","rrule","dateutil"],"install":[{"cmd":"pip install django-recurrence","lang":"bash","label":"Install with pip"}],"dependencies":[{"reason":"Core framework integration as a model field and form widget.","package":"Django"},{"reason":"Provides the underlying recurrence rule logic (rrule) which django-recurrence wraps.","package":"python-dateutil","optional":false}],"imports":[{"symbol":"RecurrenceField","correct":"from recurrence.fields import RecurrenceField"},{"note":"Used in forms for creating recurrence objects programmatically, distinct from the field itself.","symbol":"Recurrence","correct":"from recurrence.forms import Recurrence"}],"quickstart":{"code":"import os\nfrom django.conf import settings\nfrom django.db import models\n\n# Minimal Django setup for demonstration\nif not settings.configured:\n    settings.configure(\n        INSTALLED_APPS=[\n            'django.contrib.auth',\n            'django.contrib.contenttypes',\n            'recurrence' # Add 'recurrence' to INSTALLED_APPS\n        ],\n        DATABASES={'default': {'ENGINE': 'django.db.backends.sqlite3', 'NAME': ':memory:'}},\n        SECRET_KEY=os.environ.get('DJANGO_SECRET_KEY', 'a-very-secret-key-for-testing'),\n        USE_TZ=True # Recommended for date/time handling\n    )\n\nimport django\ndjango.setup()\n\nfrom recurrence.fields import RecurrenceField\nfrom datetime import date, datetime\n\nclass Event(models.Model):\n    title = models.CharField(max_length=200)\n    start_date = models.DateField(default=date.today)\n    recurrences = RecurrenceField()\n\n    class Meta:\n        app_label = 'myapp' # Required for minimal Django setup\n\n    def __str__(self):\n        return self.title\n\n# Create an event (example for admin/programmatic creation)\n# In a real app, this would be handled via forms/admin\nweekly_event = Event.objects.create(\n    title=\"Weekly Meeting\",\n    recurrences=RecurrenceField().compress_rules([\n        \"RRULE:FREQ=WEEKLY;BYDAY=MO,WE,FR;COUNT=10\",\n        \"RDATE:20260420T090000\", # Explicit date/time for specific occurrence\n        \"EXDATE:20260501T090000\" # Exclude a specific date\n    ])\n)\n\n# Retrieve occurrences for the event\n# Note: RecurrenceField itself deals with recurrences, not specific time info from start_date/time.\n# When using .between(), it's crucial to set dtstart for past occurrences.\nstart_range = datetime(2026, 4, 1, 0, 0, 0)\nend_range = datetime(2026, 6, 30, 23, 59, 59)\n\nprint(f\"Occurrences for '{weekly_event.title}' between {start_range.date()} and {end_range.date()}:\")\nfor occ_date in weekly_event.recurrences.between(start_range, end_range, dtstart=start_range, inc=True):\n    print(f\"- {occ_date.date()}\")\n\n# Example of getting the next occurrence\nnext_occurrence = weekly_event.recurrences.after(datetime.now())\nif next_occurrence:\n    print(f\"\\nThe next occurrence after now is: {next_occurrence.date()}\")\n","lang":"python","description":"This quickstart demonstrates how to define a model with `RecurrenceField`, populate it with a basic weekly recurrence rule, and then retrieve occurrences within a date range. It also highlights the importance of setting `dtstart` when querying for occurrences across a range, especially for past events."},"warnings":[{"fix":"Ensure your project uses Python 3.9+ and Django 4.2+ (preferably 5.2+ for the latest support) before upgrading to django-recurrence 1.13 or newer.","message":"Version 1.13 dropped support for Python <= 3.9 and Django <= 4.2.","severity":"breaking","affected_versions":"1.13 and higher"},{"fix":"Upgrade your Django project to version 4.0 or newer and Python to 3.9 or newer before installing or upgrading to django-recurrence 1.12 or newer.","message":"Version 1.12 dropped support for Django < 4 and Python < 3.9.","severity":"breaking","affected_versions":"1.12 and higher"},{"fix":"Always explicitly provide the `dtstart` parameter (e.g., `dtstart=datetime(year, month, day)`) to specify the desired start of the recurrence pattern for accurate results across the full range you intend to query. Set `inc=True` if you want to include the `dtstart` or `dtend` date in the results if it's an occurrence.","message":"When querying recurrence occurrences using methods like `between()`, `before()`, or `after()`, omitting the `dtstart` parameter can lead to unexpected results, as it may implicitly default to the current time, thus ignoring occurrences before `datetime.now()`.","severity":"gotcha","affected_versions":"All versions"},{"fix":"If your application requires precise time and timezone handling for recurring events, ensure your Django project is configured for timezone support (`USE_TZ = True`), and consider storing event start/end times in a `DateTimeField` rather than a `TimeField` for better integration and timezone awareness, managing the `datetime` objects returned by recurrence. Explicitly set `tzinfo` when creating `datetime` objects for recurrence calculations.","message":"The `RecurrenceField` primarily defines the *pattern* of recurrence and does not inherently manage specific time information (e.g., `start_time`) or timezone awareness for individual occurrences. It wraps `dateutil.rrule`, which generates `datetime` objects. Combining it with naive Django `TimeField`s can lead to timezone-related issues.","severity":"gotcha","affected_versions":"All versions"}],"env_vars":null,"last_verified":"2026-04-16T00:00:00.000Z","next_check":"2026-07-15T00:00:00.000Z","problems":[{"fix":"1. Add `'recurrence'` to your `INSTALLED_APPS`. 2. Ensure `django.contrib.staticfiles` is also in `INSTALLED_APPS` and run `python manage.py collectstatic`. 3. In your `urls.py`, include the `javascript_catalog` view: `from django.urls import re_path as url; from django.views.i18n import JavaScriptCatalog; js_info_dict = {'packages': ('recurrence', )}; urlpatterns += [url(r'^jsi18n/$', JavaScriptCatalog.as_view(), js_info_dict), ]`. 4. In your template, include `{{ form.media }}` within the `<head>` section.","cause":"The necessary JavaScript and CSS static files, along with the `javascript_catalog` URL, are not correctly included in your project or templates.","error":"RecurrenceField is not rendered correctly in Django admin or forms (missing JavaScript widget)."},{"fix":"First, install the package: `pip install django-recurrence`. Then, ensure `'recurrence'` is included in your `INSTALLED_APPS` tuple in your Django project's `settings.py` file.","cause":"The `django-recurrence` library is not installed, or `recurrence` is not added to `INSTALLED_APPS`.","error":"ImportError: No module named 'recurrence.fields'"},{"fix":"To delete a single occurrence, you must add an `EXDATE` (Exclusion Date) property to the recurrence rule for that specific date. To edit a single occurrence (e.g., change its time or title), you typically treat it as an `EXDATE` and create a new, separate single-day event (or `RDATE`) for the modified occurrence, while leaving the main recurrence rule untouched.","cause":"The library works by defining rules, and modifying a single occurrence requires adding an explicit exception to that rule, rather than directly editing an 'instance'.","error":"I can create recurring events, but how do I delete or edit a *single* occurrence without affecting the whole series?"}]}