Skip to content

Commit d65d0c6

Browse files
954-Ivoryauvipy
andauthored
Fixed signals can not connect to OneToOneField (#572) (#573)
* Fixed signals can not connect to OneToOneField (#572) * Remove unused import. * Changed `PeriodicTasks.pre_save` and `PeriodicTasks.pre_delete` in `PeriodicTasks.save` and `PeriodicTasks.delete` * Update django_celery_beat/models.py * Append the unit-test * Correction of notes * Append test-case for: O2O-rel instance be deleted * Add the docs * Format code according to `pycodestyle` Co-authored-by: Asif Saif Uddin <[email protected]>
1 parent e2e97dd commit d65d0c6

File tree

8 files changed

+143
-25
lines changed

8 files changed

+143
-25
lines changed

django_celery_beat/apps.py

+4
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,7 @@ class BeatConfig(AppConfig):
1212
label = 'django_celery_beat'
1313
verbose_name = _('Periodic Tasks')
1414
default_auto_field = 'django.db.models.AutoField'
15+
16+
def ready(self):
17+
from .signals import signals_connect
18+
signals_connect()

django_celery_beat/models.py

+5-21
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
from django.core.exceptions import MultipleObjectsReturned, ValidationError
1212
from django.core.validators import MaxValueValidator, MinValueValidator
1313
from django.db import models
14-
from django.db.models import signals
1514
from django.utils.translation import gettext_lazy as _
1615

1716
from . import managers, validators
@@ -586,6 +585,11 @@ def save(self, *args, **kwargs):
586585
self._clean_expires()
587586
self.validate_unique()
588587
super().save(*args, **kwargs)
588+
PeriodicTasks.changed(self)
589+
590+
def delete(self, *args, **kwargs):
591+
super().delete(*args, **kwargs)
592+
PeriodicTasks.changed(self)
589593

590594
def _clean_expires(self):
591595
if self.expire_seconds is not None and self.expires:
@@ -619,23 +623,3 @@ def schedule(self):
619623
return self.solar.schedule
620624
if self.clocked:
621625
return self.clocked.schedule
622-
623-
624-
signals.pre_delete.connect(PeriodicTasks.changed, sender=PeriodicTask)
625-
signals.pre_save.connect(PeriodicTasks.changed, sender=PeriodicTask)
626-
signals.pre_delete.connect(
627-
PeriodicTasks.update_changed, sender=IntervalSchedule)
628-
signals.post_save.connect(
629-
PeriodicTasks.update_changed, sender=IntervalSchedule)
630-
signals.post_delete.connect(
631-
PeriodicTasks.update_changed, sender=CrontabSchedule)
632-
signals.post_save.connect(
633-
PeriodicTasks.update_changed, sender=CrontabSchedule)
634-
signals.post_delete.connect(
635-
PeriodicTasks.update_changed, sender=SolarSchedule)
636-
signals.post_save.connect(
637-
PeriodicTasks.update_changed, sender=SolarSchedule)
638-
signals.post_delete.connect(
639-
PeriodicTasks.update_changed, sender=ClockedSchedule)
640-
signals.post_save.connect(
641-
PeriodicTasks.update_changed, sender=ClockedSchedule)

django_celery_beat/signals.py

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
def signals_connect():
2+
"""
3+
Connect to signals.
4+
"""
5+
from django.db.models import signals
6+
from .models import (
7+
ClockedSchedule,
8+
PeriodicTask,
9+
PeriodicTasks,
10+
IntervalSchedule,
11+
CrontabSchedule,
12+
SolarSchedule
13+
)
14+
15+
signals.pre_save.connect(
16+
PeriodicTasks.changed, sender=PeriodicTask
17+
)
18+
signals.pre_delete.connect(
19+
PeriodicTasks.changed, sender=PeriodicTask
20+
)
21+
22+
signals.post_save.connect(
23+
PeriodicTasks.update_changed, sender=IntervalSchedule
24+
)
25+
signals.pre_delete.connect(
26+
PeriodicTasks.update_changed, sender=IntervalSchedule
27+
)
28+
29+
signals.post_save.connect(
30+
PeriodicTasks.update_changed, sender=CrontabSchedule
31+
)
32+
signals.post_delete.connect(
33+
PeriodicTasks.update_changed, sender=CrontabSchedule
34+
)
35+
36+
signals.post_save.connect(
37+
PeriodicTasks.update_changed, sender=SolarSchedule
38+
)
39+
signals.post_delete.connect(
40+
PeriodicTasks.update_changed, sender=SolarSchedule
41+
)
42+
43+
signals.post_save.connect(
44+
PeriodicTasks.update_changed, sender=ClockedSchedule
45+
)
46+
signals.post_delete.connect(
47+
PeriodicTasks.update_changed, sender=ClockedSchedule
48+
)

t/proj/migrations/0001_initial.py

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Generated by Django 4.0.7 on 2022-10-13 05:09
2+
3+
from django.db import migrations, models
4+
import django.db.models.deletion
5+
6+
7+
class Migration(migrations.Migration):
8+
9+
initial = True
10+
11+
dependencies = [
12+
('django_celery_beat', '0016_alter_crontabschedule_timezone'),
13+
]
14+
15+
operations = [
16+
migrations.CreateModel(
17+
name='O2OToPeriodicTasks',
18+
fields=[
19+
('periodictask_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='django_celery_beat.periodictask')),
20+
],
21+
bases=('django_celery_beat.periodictask',),
22+
),
23+
]

t/proj/migrations/__init__.py

Whitespace-only changes.

t/proj/models.py

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
from django_celery_beat.models import PeriodicTask
2+
3+
4+
class O2OToPeriodicTasks(PeriodicTask):
5+
"""
6+
The test-case model of OneToOne relation.
7+
"""
8+
pass

t/proj/settings.py

+1-4
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
'django.contrib.messages',
4949
'django.contrib.staticfiles',
5050
'django_celery_beat',
51+
't.proj',
5152
]
5253

5354
MIDDLEWARE = [
@@ -79,7 +80,6 @@
7980

8081
WSGI_APPLICATION = 't.proj.wsgi.application'
8182

82-
8383
# Database
8484
# https://docs.djangoproject.com/en/1.9/ref/settings/#databases
8585

@@ -93,7 +93,6 @@
9393
}
9494
}
9595

96-
9796
# Password validation
9897
# https://docs.djangoproject.com/en/1.9/ref/settings/#auth-password-validators
9998

@@ -102,7 +101,6 @@
102101
AUTH_PASSWORD_VALIDATORS = [
103102
]
104103

105-
106104
# Internationalization
107105
# https://docs.djangoproject.com/en/1.9/topics/i18n/
108106

@@ -116,7 +114,6 @@
116114

117115
USE_TZ = True
118116

119-
120117
# Static files (CSS, JavaScript, Images)
121118
# https://docs.djangoproject.com/en/1.9/howto/static-files/
122119

t/unit/test_models.py

+54
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
import datetime
22
import os
3+
34
try:
45
from zoneinfo import available_timezones, ZoneInfo
56
except ImportError:
67
from backports.zoneinfo import available_timezones, ZoneInfo
78

9+
import pytest
10+
811
from celery import schedules
912
from django.test import TestCase, override_settings
1013
from django.apps import apps
@@ -22,7 +25,10 @@
2225
CrontabSchedule,
2326
ClockedSchedule,
2427
IntervalSchedule,
28+
PeriodicTasks,
29+
DAYS,
2530
)
31+
from t.proj.models import O2OToPeriodicTasks
2632

2733

2834
class MigrationTests(TestCase):
@@ -159,3 +165,51 @@ def test_timezone_format(self):
159165
clocked_time=tz_info)
160166
# testnig str(schedule) calls make_aware() internally
161167
assert str(schedule.clocked_time) == str(schedule)
168+
169+
170+
@pytest.mark.django_db()
171+
class OneToOneRelTestCase(TestCase):
172+
"""
173+
Make sure that when OneToOne relation Model changed,
174+
the `PeriodicTasks.last_update` will be update.
175+
"""
176+
177+
@classmethod
178+
def setUpTestData(cls):
179+
super().setUpTestData()
180+
cls.interval_schedule = IntervalSchedule.objects.create(
181+
every=10, period=DAYS
182+
)
183+
184+
def test_trigger_update_when_saved(self):
185+
o2o_to_periodic_tasks = O2OToPeriodicTasks.objects.create(
186+
name='name1',
187+
task='task1',
188+
enabled=True,
189+
interval=self.interval_schedule
190+
)
191+
not_changed_dt = PeriodicTasks.last_change()
192+
o2o_to_periodic_tasks.enabled = True # Change something on instance.
193+
o2o_to_periodic_tasks.save()
194+
has_changed_dt = PeriodicTasks.last_change()
195+
self.assertTrue(
196+
not_changed_dt != has_changed_dt,
197+
'The `PeriodicTasks.last_update` has not be update.'
198+
)
199+
# Check the `PeriodicTasks` does be updated.
200+
201+
def test_trigger_update_when_deleted(self):
202+
o2o_to_periodic_tasks = O2OToPeriodicTasks.objects.create(
203+
name='name1',
204+
task='task1',
205+
enabled=True,
206+
interval=self.interval_schedule
207+
)
208+
not_changed_dt = PeriodicTasks.last_change()
209+
o2o_to_periodic_tasks.delete()
210+
has_changed_dt = PeriodicTasks.last_change()
211+
self.assertTrue(
212+
not_changed_dt != has_changed_dt,
213+
'The `PeriodicTasks.last_update` has not be update.'
214+
)
215+
# Check the `PeriodicTasks` does be updated.

0 commit comments

Comments
 (0)