कई साइकिलिंग समूहों की नियमित राइड होती हैं - सोमवार सुबह का कम्यूट क्रू, महीने के पहले शनिवार की एडवेंचर राइड, या बुधवार शाम की सोशल स्पिन। अब तक, आयोजकों को प्रत्येक इवेंट मैन्युअली बनाना पड़ता था। हमारी नई आवर्ती पार्टियाँ सुविधा के साथ, आप एक बार शेड्यूल सेट कर सकते हैं और Party Onbici को स्वचालित रूप से इंस्टेंस जनरेट करने दें।
एकबारगी इवेंट की समस्या
सामुदायिक साइकिलिंग समूहों के आमतौर पर पूर्वानुमेय शेड्यूल होते हैं:
- “हर मंगलवार और गुरुवार सुबह 6:30 बजे”
- “हर महीने का पहला रविवार”
- “हर दूसरे शनिवार सुबह”
इन इवेंट को मैन्युअली बनाना थकाऊ, त्रुटि-प्रवण है, और पुनरावृत्तियों में सुसंगत मार्गों और सेटिंग्स को बनाए रखना कठिन बनाता है।
iCalendar RRULE का परिचय
हमने अपना आवर्ती इवेंट सिस्टम iCalendar RRULE मानक (RFC 5545) पर बनाया। यह वही फॉर्मेट है जो Google Calendar, Apple Calendar और Outlook द्वारा उपयोग किया जाता है - व्यापक कैलेंडर इकोसिस्टम के साथ संगतता सुनिश्चित करना।
उदाहरण पुनरावृत्ति पैटर्न
1
2
3
4
5
6
7
8
9
10
11
| RRULE:FREQ=WEEKLY;BYDAY=MO,WE,FR
→ हर सोमवार, बुधवार और शुक्रवार
RRULE:FREQ=MONTHLY;BYDAY=1SA
→ हर महीने का पहला शनिवार
RRULE:FREQ=WEEKLY;INTERVAL=2;BYDAY=SU
→ हर दूसरा रविवार
RRULE:FREQ=DAILY;COUNT=10
→ 10 बार के लिए दैनिक
|
डेटा मॉडल
एक RecurringParty एक टेम्पलेट के रूप में कार्य करता है जो Party इंस्टेंस जनरेट करता है:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| class RecurringParty(models.Model):
name = models.CharField(max_length=255)
# शेड्यूल कॉन्फ़िगरेशन
start_date = models.DateField()
end_date = models.DateField(null=True, blank=True)
max_occurrences = models.PositiveIntegerField(null=True, blank=True)
recurrence = RecurrenceField() # RRULE पैटर्न
# टेम्पलेट फ़ील्ड (प्रत्येक इंस्टेंस में कॉपी)
departure_time = models.TimeField()
arrival_time = models.TimeField()
origin = PointField()
destination = PointField()
route = models.JSONField()
difficulty = models.CharField(choices=DIFFICULTY_CHOICES)
# ... अन्य पार्टी विशेषताएं
is_active = models.BooleanField(default=True)
|
प्रत्येक जनरेटेड Party इंस्टेंस अपने पैरेंट से जुड़ता है:
1
2
3
4
5
6
7
8
9
10
11
12
| class Party(models.Model):
# मौजूदा फ़ील्ड...
# आवर्ती पार्टी समर्थन
scheduled_date = models.DateField(null=True, blank=True)
recurring_parent = models.ForeignKey(
RecurringParty,
on_delete=models.SET_NULL,
null=True,
related_name="instances"
)
is_cancelled = models.BooleanField(default=False)
|
इंस्टेंस जनरेशन
जब एक आवर्ती पार्टी बनाई जाती है या शेड्यूल बदलता है, हम आगामी अवधि के लिए इंस्टेंस जनरेट करते हैं:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
| def generate_instances(self, lookahead_days: int = 30) -> list[Party]:
"""आगामी पुनरावृत्तियों के लिए पार्टी इंस्टेंस जनरेट करें।"""
occurrences = self.recurrence.between(
datetime.now().date(),
datetime.now().date() + timedelta(days=lookahead_days),
)
created = []
for date in occurrences:
# अगर इंस्टेंस पहले से मौजूद है तो छोड़ें
if self.instances.filter(scheduled_date=date).exists():
continue
# टेम्पलेट से नया पार्टी इंस्टेंस बनाएं
party = Party.objects.create(
name=f"{self.name} - {date.strftime('%B %d')}",
scheduled_date=date,
recurring_parent=self,
departure_time=self.departure_time,
arrival_time=self.arrival_time,
origin=self.origin,
destination=self.destination,
route=self.route,
# ... अन्य टेम्पलेट फ़ील्ड कॉपी करें
)
created.append(party)
return created
|
Celery Beat के साथ स्वचालित जनरेशन
एक दैनिक Celery टास्क इंस्टेंस को अप-टू-डेट रखता है:
1
2
3
4
5
6
7
8
9
| @shared_task
def generate_recurring_party_instances():
"""सभी सक्रिय आवर्ती पार्टियों के लिए पार्टी इंस्टेंस जनरेट करें।"""
for recurring_party in RecurringParty.objects.filter(is_active=True):
created = recurring_party.generate_instances(lookahead_days=30)
if created:
logger.info(
f"{recurring_party.name} के लिए {len(created)} इंस्टेंस जनरेट किए"
)
|
Celery Beat शेड्यूल इसे मध्यरात्रि में चलाता है:
1
2
3
4
5
6
| CELERY_BEAT_SCHEDULE = {
"generate-recurring-party-instances": {
"task": "party_onbici.apps.party.tasks.generate_recurring_party_instances",
"schedule": crontab(hour=0, minute=0), # मध्यरात्रि में दैनिक
},
}
|
यूजर इंटरफेस
आवर्ती पार्टी बनाना
फॉर्म RRULE पैटर्न बनाने के लिए django-recurrence विजेट का उपयोग करता है:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| class RecurringPartyForm(forms.ModelForm):
recurrence = RecurrenceField(
label="पुनरावृत्ति पैटर्न",
help_text="सेट करें कि यह पार्टी कब दोहरानी चाहिए।",
required=True,
)
class Meta:
model = RecurringParty
fields = [
"name", "start_date", "end_date", "recurrence",
"departure_time", "arrival_time",
"origin", "destination", "description",
"difficulty", "gender", "privacy",
]
|
विजेट सामान्य पैटर्न के लिए एक सहज इंटरफ़ेस प्रदान करता है:
- दैनिक / साप्ताहिक / मासिक / वार्षिक
- सप्ताह के विशिष्ट दिन
- क्रमसूचक पैटर्न (पहला, दूसरा, अंतिम)
- कस्टम अंतराल (हर 2 सप्ताह)
- समाप्ति शर्तें (तिथि तक, N पुनरावृत्तियों के बाद, या कभी नहीं)
इंस्टेंस प्रबंधन
आयोजक सभी जनरेटेड इंस्टेंस देख सकते हैं और:
- व्यक्तिगत इंस्टेंस संपादित करें - एक पुनरावृत्ति के लिए मार्ग या समय बदलें
- इंस्टेंस रद्द करें - विशिष्ट तिथियों को रद्द के रूप में चिह्नित करें
- इंस्टेंस पुनर्जनरेट करें - अगले 30 दिनों के लिए मैन्युअली जनरेशन ट्रिगर करें
एज केस हैंडलिंग
टाइम ज़ोन जागरूकता
सभी तिथियाँ आयोजक के कॉन्फ़िगर किए गए टाइमज़ोन में संग्रहीत होती हैं और दर्शक के स्थानीय समय में प्रदर्शित होती हैं:
1
2
3
| # टाइमज़ोन-अवेयर तिथियों का उपयोग करके इंस्टेंस जनरेट करें
local_tz = get_current_timezone()
today = timezone.now().astimezone(local_tz).date()
|
छुट्टी और अपवाद हैंडलिंग
उपयोगकर्ता आवर्ती पैटर्न को प्रभावित किए बिना व्यक्तिगत इंस्टेंस रद्द कर सकते हैं:
1
2
3
| party = recurring_party.instances.get(scheduled_date=holiday_date)
party.is_cancelled = True
party.save()
|
रद्द किए गए इंस्टेंस अभी भी एक विज़ुअल इंडिकेटर के साथ सूची में दिखाई देते हैं, भ्रम को रोकते हैं।
अनाथ इंस्टेंस
यदि कोई आवर्ती पार्टी हटा दी जाती है, तो जनरेट किए गए इंस्टेंस वैकल्पिक रूप से संरक्षित किए जा सकते हैं:
1
2
3
4
5
6
7
8
9
10
11
| def form_valid(self, form):
delete_instances = request.POST.get("delete_instances") == "true"
if delete_instances:
# भविष्य के इंस्टेंस को सॉफ्ट-डिलीट करें
recurring_party.instances.filter(
scheduled_date__gte=date.today(),
deleted_at__isnull=True,
).update(deleted_at=timezone.now())
recurring_party.delete()
|
यूजर अनुभव
साप्ताहिक राइड बनाने में बस कुछ कदम लगते हैं:
- डैशबोर्ड → आवर्ती पार्टियाँ → बनाएं पर जाएं
- अपनी पार्टी का विवरण सेट करें (मार्ग, समय, कठिनाई)
- पुनरावृत्ति पैटर्न कॉन्फ़िगर करें (जैसे, “हर शनिवार सुबह 8 बजे”)
- प्रारंभ तिथि और वैकल्पिक समाप्ति तिथि सेट करें
- सेव करें - इंस्टेंस स्वचालित रूप से जनरेट हो जाते हैं!
सिस्टम 30 दिन पहले पार्टी इंस्टेंस बनाता है, और Celery समय बीतने के साथ नए जनरेट करता रहता है।
साइकिलिंग समुदायों के लिए लाभ
- सेट करें और भूल जाएं - अब साप्ताहिक इवेंट निर्माण नहीं
- संगति - समान मार्ग, समान समय, समान सेटिंग्स
- लचीलापन - व्यक्तिगत पुनरावृत्तियों को संपादित या रद्द करें
- खोज - राइडर्स आसानी से नियमित ग्रुप राइड ढूंढ सकते हैं
- कैलेंडर एकीकरण - अपने कैलेंडर ऐप में आवर्ती इवेंट की सदस्यता लें
अपनी नियमित राइड सेट अप करने के लिए तैयार हैं? आवर्ती पार्टी बनाएं और शेड्यूलिंग हमें संभालने दें!