Skip to content

Commit

Permalink
Fixed signals can not connect to OneToOneField (#572) (#573)
Browse files Browse the repository at this point in the history
* 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 <auvipy@gmail.com>
  • Loading branch information
954-Ivory and auvipy authored Oct 13, 2022
1 parent e2e97dd commit d65d0c6
Show file tree
Hide file tree
Showing 8 changed files with 143 additions and 25 deletions.
4 changes: 4 additions & 0 deletions django_celery_beat/apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,7 @@ class BeatConfig(AppConfig):
label = 'django_celery_beat'
verbose_name = _('Periodic Tasks')
default_auto_field = 'django.db.models.AutoField'

def ready(self):
from .signals import signals_connect
signals_connect()
26 changes: 5 additions & 21 deletions django_celery_beat/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
from django.core.exceptions import MultipleObjectsReturned, ValidationError
from django.core.validators import MaxValueValidator, MinValueValidator
from django.db import models
from django.db.models import signals
from django.utils.translation import gettext_lazy as _

from . import managers, validators
Expand Down Expand Up @@ -586,6 +585,11 @@ def save(self, *args, **kwargs):
self._clean_expires()
self.validate_unique()
super().save(*args, **kwargs)
PeriodicTasks.changed(self)

def delete(self, *args, **kwargs):
super().delete(*args, **kwargs)
PeriodicTasks.changed(self)

def _clean_expires(self):
if self.expire_seconds is not None and self.expires:
Expand Down Expand Up @@ -619,23 +623,3 @@ def schedule(self):
return self.solar.schedule
if self.clocked:
return self.clocked.schedule


signals.pre_delete.connect(PeriodicTasks.changed, sender=PeriodicTask)
signals.pre_save.connect(PeriodicTasks.changed, sender=PeriodicTask)
signals.pre_delete.connect(
PeriodicTasks.update_changed, sender=IntervalSchedule)
signals.post_save.connect(
PeriodicTasks.update_changed, sender=IntervalSchedule)
signals.post_delete.connect(
PeriodicTasks.update_changed, sender=CrontabSchedule)
signals.post_save.connect(
PeriodicTasks.update_changed, sender=CrontabSchedule)
signals.post_delete.connect(
PeriodicTasks.update_changed, sender=SolarSchedule)
signals.post_save.connect(
PeriodicTasks.update_changed, sender=SolarSchedule)
signals.post_delete.connect(
PeriodicTasks.update_changed, sender=ClockedSchedule)
signals.post_save.connect(
PeriodicTasks.update_changed, sender=ClockedSchedule)
48 changes: 48 additions & 0 deletions django_celery_beat/signals.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
def signals_connect():
"""
Connect to signals.
"""
from django.db.models import signals
from .models import (
ClockedSchedule,
PeriodicTask,
PeriodicTasks,
IntervalSchedule,
CrontabSchedule,
SolarSchedule
)

signals.pre_save.connect(
PeriodicTasks.changed, sender=PeriodicTask
)
signals.pre_delete.connect(
PeriodicTasks.changed, sender=PeriodicTask
)

signals.post_save.connect(
PeriodicTasks.update_changed, sender=IntervalSchedule
)
signals.pre_delete.connect(
PeriodicTasks.update_changed, sender=IntervalSchedule
)

signals.post_save.connect(
PeriodicTasks.update_changed, sender=CrontabSchedule
)
signals.post_delete.connect(
PeriodicTasks.update_changed, sender=CrontabSchedule
)

signals.post_save.connect(
PeriodicTasks.update_changed, sender=SolarSchedule
)
signals.post_delete.connect(
PeriodicTasks.update_changed, sender=SolarSchedule
)

signals.post_save.connect(
PeriodicTasks.update_changed, sender=ClockedSchedule
)
signals.post_delete.connect(
PeriodicTasks.update_changed, sender=ClockedSchedule
)
23 changes: 23 additions & 0 deletions t/proj/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Generated by Django 4.0.7 on 2022-10-13 05:09

from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

initial = True

dependencies = [
('django_celery_beat', '0016_alter_crontabschedule_timezone'),
]

operations = [
migrations.CreateModel(
name='O2OToPeriodicTasks',
fields=[
('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')),
],
bases=('django_celery_beat.periodictask',),
),
]
Empty file added t/proj/migrations/__init__.py
Empty file.
8 changes: 8 additions & 0 deletions t/proj/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from django_celery_beat.models import PeriodicTask


class O2OToPeriodicTasks(PeriodicTask):
"""
The test-case model of OneToOne relation.
"""
pass
5 changes: 1 addition & 4 deletions t/proj/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
'django.contrib.messages',
'django.contrib.staticfiles',
'django_celery_beat',
't.proj',
]

MIDDLEWARE = [
Expand Down Expand Up @@ -79,7 +80,6 @@

WSGI_APPLICATION = 't.proj.wsgi.application'


# Database
# https://docs.djangoproject.com/en/1.9/ref/settings/#databases

Expand All @@ -93,7 +93,6 @@
}
}


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

Expand All @@ -102,7 +101,6 @@
AUTH_PASSWORD_VALIDATORS = [
]


# Internationalization
# https://docs.djangoproject.com/en/1.9/topics/i18n/

Expand All @@ -116,7 +114,6 @@

USE_TZ = True


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

Expand Down
54 changes: 54 additions & 0 deletions t/unit/test_models.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import datetime
import os

try:
from zoneinfo import available_timezones, ZoneInfo
except ImportError:
from backports.zoneinfo import available_timezones, ZoneInfo

import pytest

from celery import schedules
from django.test import TestCase, override_settings
from django.apps import apps
Expand All @@ -22,7 +25,10 @@
CrontabSchedule,
ClockedSchedule,
IntervalSchedule,
PeriodicTasks,
DAYS,
)
from t.proj.models import O2OToPeriodicTasks


class MigrationTests(TestCase):
Expand Down Expand Up @@ -159,3 +165,51 @@ def test_timezone_format(self):
clocked_time=tz_info)
# testnig str(schedule) calls make_aware() internally
assert str(schedule.clocked_time) == str(schedule)


@pytest.mark.django_db()
class OneToOneRelTestCase(TestCase):
"""
Make sure that when OneToOne relation Model changed,
the `PeriodicTasks.last_update` will be update.
"""

@classmethod
def setUpTestData(cls):
super().setUpTestData()
cls.interval_schedule = IntervalSchedule.objects.create(
every=10, period=DAYS
)

def test_trigger_update_when_saved(self):
o2o_to_periodic_tasks = O2OToPeriodicTasks.objects.create(
name='name1',
task='task1',
enabled=True,
interval=self.interval_schedule
)
not_changed_dt = PeriodicTasks.last_change()
o2o_to_periodic_tasks.enabled = True # Change something on instance.
o2o_to_periodic_tasks.save()
has_changed_dt = PeriodicTasks.last_change()
self.assertTrue(
not_changed_dt != has_changed_dt,
'The `PeriodicTasks.last_update` has not be update.'
)
# Check the `PeriodicTasks` does be updated.

def test_trigger_update_when_deleted(self):
o2o_to_periodic_tasks = O2OToPeriodicTasks.objects.create(
name='name1',
task='task1',
enabled=True,
interval=self.interval_schedule
)
not_changed_dt = PeriodicTasks.last_change()
o2o_to_periodic_tasks.delete()
has_changed_dt = PeriodicTasks.last_change()
self.assertTrue(
not_changed_dt != has_changed_dt,
'The `PeriodicTasks.last_update` has not be update.'
)
# Check the `PeriodicTasks` does be updated.

0 comments on commit d65d0c6

Please sign in to comment.