Birçok bisiklet grubunun düzenli sürüşleri vardır - Pazartesi sabahı işe gidiş ekibi, ayın ilk Cumartesi macera sürüşü veya Çarşamba akşamı sosyal tur. Şimdiye kadar, organizatörler her etkinliği manuel olarak oluşturmak zorundaydı. Yeni Tekrarlayan Partiler özelliğimizle, bir kez zamanlama ayarlayabilir ve Party Onbici’nin otomatik olarak örnekler oluşturmasına izin verebilirsiniz.
Tek Seferlik Etkinliklerin Sorunu
Topluluk bisiklet gruplarının genellikle öngörülebilir zamanlamaları vardır:
- “Her Salı ve Perşembe sabah 6:30’da”
- “Her ayın ilk Pazar günü”
- “Her iki haftada bir Cumartesi sabahı”
Bu etkinlikleri manuel olarak oluşturmak sıkıcı, hataya açık ve olaylar arasında tutarlı rotaları ve ayarları korumayı zorlaştırır.
iCalendar RRULE ile Tanışın
Tekrarlayan etkinlik sistemimizi iCalendar RRULE standardı (RFC 5545) üzerine kurduk. Bu, Google Calendar, Apple Calendar ve Outlook tarafından kullanılan aynı formattır - daha geniş takvim ekosistemiyle uyumluluk sağlar.
Örnek Tekrarlama Kalıpları
1
2
3
4
5
6
7
8
9
10
11
| RRULE:FREQ=WEEKLY;BYDAY=MO,WE,FR
→ Her Pazartesi, Çarşamba ve Cuma
RRULE:FREQ=MONTHLY;BYDAY=1SA
→ Her ayın ilk Cumartesisi
RRULE:FREQ=WEEKLY;INTERVAL=2;BYDAY=SU
→ Her iki haftada bir Pazar
RRULE:FREQ=DAILY;COUNT=10
→ 10 kez için günlük
|
Veri Modeli
Bir RecurringParty, Party örnekleri oluşturan bir şablon görevi görür:
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)
# Zamanlama yapılandırması
start_date = models.DateField()
end_date = models.DateField(null=True, blank=True)
max_occurrences = models.PositiveIntegerField(null=True, blank=True)
recurrence = RecurrenceField() # RRULE kalıbı
# Şablon alanları (her örneğe kopyalanır)
departure_time = models.TimeField()
arrival_time = models.TimeField()
origin = PointField()
destination = PointField()
route = models.JSONField()
difficulty = models.CharField(choices=DIFFICULTY_CHOICES)
# ... diğer parti özellikleri
is_active = models.BooleanField(default=True)
|
Oluşturulan her Party örneği üst öğesine geri bağlanır:
1
2
3
4
5
6
7
8
9
10
11
12
| class Party(models.Model):
# Mevcut alanlar...
# Tekrarlayan parti desteği
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)
|
Örnek Oluşturma
Tekrarlayan bir parti oluşturulduğunda veya zamanlama değiştiğinde, yaklaşan dönem için örnekler oluştururuz:
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]:
"""Yaklaşan olaylar için parti örnekleri oluştur."""
occurrences = self.recurrence.between(
datetime.now().date(),
datetime.now().date() + timedelta(days=lookahead_days),
)
created = []
for date in occurrences:
# Örnek zaten varsa atla
if self.instances.filter(scheduled_date=date).exists():
continue
# Şablondan yeni parti örneği oluştur
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,
# ... diğer şablon alanlarını kopyala
)
created.append(party)
return created
|
Celery Beat ile Otomatik Oluşturma
Günlük bir Celery görevi örnekleri güncel tutar:
1
2
3
4
5
6
7
8
9
| @shared_task
def generate_recurring_party_instances():
"""Tüm aktif tekrarlayan partiler için parti örnekleri oluştur."""
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} için {len(created)} örnek oluşturuldu"
)
|
Celery Beat zamanlaması bunu gece yarısı çalıştırır:
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), # Günlük gece yarısı
},
}
|
Kullanıcı Arayüzü
Tekrarlayan Parti Oluşturma
Form, RRULE kalıpları oluşturmak için django-recurrence widget’ını kullanır:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| class RecurringPartyForm(forms.ModelForm):
recurrence = RecurrenceField(
label="Tekrarlama kalıbı",
help_text="Bu partinin ne zaman tekrarlanacağını ayarlayın.",
required=True,
)
class Meta:
model = RecurringParty
fields = [
"name", "start_date", "end_date", "recurrence",
"departure_time", "arrival_time",
"origin", "destination", "description",
"difficulty", "gender", "privacy",
]
|
Widget, yaygın kalıplar için sezgisel bir arayüz sağlar:
- Günlük / Haftalık / Aylık / Yıllık
- Haftanın belirli günleri
- Sıralı kalıplar (birinci, ikinci, son)
- Özel aralıklar (her 2 haftada bir)
- Bitiş koşulları (tarihe kadar, N olaydan sonra veya hiçbir zaman)
Örnekleri Yönetme
Organizatörler tüm oluşturulan örnekleri görüntüleyebilir ve:
- Bireysel örnekleri düzenle - Bir olay için rota veya zamanı değiştir
- Örnekleri iptal et - Belirli tarihleri iptal edildi olarak işaretle
- Örnekleri yeniden oluştur - Sonraki 30 gün için manuel olarak oluşturmayı tetikle
Uç Durumları Ele Alma
Saat Dilimi Farkındalığı
Tüm tarihler organizatörün yapılandırılmış saat diliminde saklanır ve izleyicinin yerel saatinde görüntülenir:
1
2
3
| # Saat dilimi farkındalıklı tarihler kullanarak örnekler oluştur
local_tz = get_current_timezone()
today = timezone.now().astimezone(local_tz).date()
|
Tatil ve İstisna İşleme
Kullanıcılar, tekrarlayan kalıbı etkilemeden bireysel örnekleri iptal edebilir:
1
2
3
| party = recurring_party.instances.get(scheduled_date=holiday_date)
party.is_cancelled = True
party.save()
|
İptal edilen örnekler hala görsel bir göstergeyle listede görünür, karışıklığı önler.
Yetim Örnekler
Tekrarlayan bir parti silinirse, oluşturulan örnekler isteğe bağlı olarak korunabilir:
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:
# Gelecek örnekleri yumuşak silme
recurring_party.instances.filter(
scheduled_date__gte=date.today(),
deleted_at__isnull=True,
).update(deleted_at=timezone.now())
recurring_party.delete()
|
Kullanıcı Deneyimi
Haftalık sürüş oluşturmak sadece birkaç adım alır:
- Gösterge Paneli → Tekrarlayan Partiler → Oluştur‘a gidin
- Parti ayrıntılarınızı ayarlayın (rota, zamanlar, zorluk)
- Tekrarlama kalıbını yapılandırın (ör. “Her Cumartesi sabah 8’de”)
- Başlangıç tarihini ve isteğe bağlı bitiş tarihini ayarlayın
- Kaydet - örnekler otomatik olarak oluşturulur!
Sistem 30 gün öncesinden parti örnekleri oluşturur ve Celery zaman geçtikçe yenilerini oluşturmaya devam eder.
Bisiklet Toplulukları İçin Faydalar
- Ayarla ve unut - Artık haftalık etkinlik oluşturma yok
- Tutarlılık - Aynı rota, aynı zaman, aynı ayarlar
- Esneklik - Bireysel olayları düzenle veya iptal et
- Keşif - Bisikletçiler düzenli grup sürüşlerini kolayca bulabilir
- Takvim entegrasyonu - Takvim uygulamanızda tekrarlayan etkinliklere abone olun
Düzenli sürüşünüzü ayarlamaya hazır mısınız? Tekrarlayan parti oluşturun ve zamanlamayı bize bırakın!