Skip to content

Commit 68a1214

Browse files
authored
Merge pull request #311 from KrYpTeD974/signals_not_triggered
Fix #310 The `preference_updated` signal is now triggered when using the REST API
2 parents 3017fde + cb6884f commit 68a1214

File tree

5 files changed

+106
-12
lines changed

5 files changed

+106
-12
lines changed

docs/react_to_updates.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,15 @@ of the signal, which are:
2020
* ``name`` - the name of the changed preference
2121
* ``old_value`` - the value of the preference before changing
2222
* ``new_value`` - the value assigned to the preference after the change
23-
23+
* ``instance`` - the preference Model instance
2424
An example that just prints a message that the preference was changed is
2525
below.
2626

2727
.. code-block:: python
2828
2929
# yourapp/util.py
3030
31-
def notify_on_preference_update(sender, section, name, old_value, new_value, **kwargs):
31+
def notify_on_preference_update(sender, section, name, old_value, new_value, instance, **kwargs):
3232
print("Preference {} in section {} changed from {} to {}".format(
3333
name, section, old, new))
3434

dynamic_preferences/api/serializers.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from rest_framework import serializers
2-
from dynamic_preferences.models import GlobalPreferenceModel
2+
3+
from dynamic_preferences.signals import preference_updated
34

45

56
class PreferenceValueField(serializers.Field):
@@ -62,8 +63,17 @@ def validate_value(self, value):
6263
return value
6364

6465
def update(self, instance, validated_data):
66+
old_value = instance.value
6567
instance.value = validated_data["value"]
6668
instance.save()
69+
preference_updated.send(
70+
sender=self.__class__,
71+
section=instance.section,
72+
name=instance.name,
73+
old_value=old_value,
74+
new_value=validated_data["value"],
75+
instance=instance
76+
)
6777
return instance
6878

6979

dynamic_preferences/managers.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@ def update_db_pref(self, section, name, value):
173173
name=name,
174174
old_value=old_value,
175175
new_value=value,
176+
instance=db_pref
176177
)
177178
except self.model.DoesNotExist:
178179
return self.create_db_pref(section, name, value)

tests/test_preferences.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,8 @@ class P(StringPreference):
192192
def test_preferences_manager_signal(db):
193193
global_preferences = global_preferences_registry.manager()
194194
global_preferences["no_section"] = False
195+
pref = global_preferences.get_db_pref(name="no_section", section=None)
196+
195197
receiver = MagicMock()
196198
preference_updated.connect(receiver)
197199
global_preferences["no_section"] = True
@@ -203,4 +205,5 @@ def test_preferences_manager_signal(db):
203205
"name": "no_section",
204206
"old_value": False,
205207
"new_value": True,
208+
"instance": pref
206209
}.items() <= call_args.items()

tests/test_rest_framework.py

Lines changed: 89 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,23 @@
11
import json
2-
32
from decimal import Decimal
3+
44
from django.urls import reverse
55

6-
from dynamic_preferences.registries import global_preferences_registry as registry
6+
from dynamic_preferences.api import serializers
7+
from dynamic_preferences.api.serializers import GlobalPreferenceSerializer
8+
from dynamic_preferences.registries import \
9+
global_preferences_registry as registry
10+
from dynamic_preferences.signals import preference_updated
711
from dynamic_preferences.users.registries import (
812
user_preferences_registry as user_registry,
913
)
10-
from dynamic_preferences.api import serializers
1114
from dynamic_preferences.users.serializers import UserPreferenceSerializer
1215

16+
try:
17+
from unittest.mock import MagicMock
18+
except ImportError:
19+
from mock import MagicMock
20+
1321

1422
def test_can_serialize_preference(db):
1523
manager = registry.manager()
@@ -78,7 +86,8 @@ def test_serializer_includes_additional_data_if_any(fake_user):
7886
pref = manager.get_db_pref(section="user", name="favorite_vegetable")
7987

8088
serializer = UserPreferenceSerializer(pref)
81-
assert serializer.data["additional_data"]["choices"] == pref.preference.choices
89+
assert serializer.data["additional_data"][
90+
"choices"] == pref.preference.choices
8291

8392

8493
def test_global_preference_list_requires_permission(db, client):
@@ -129,7 +138,8 @@ def test_can_list_preferences_with_section_filter(admin_client):
129138
def test_can_detail_preference(admin_client):
130139
manager = registry.manager()
131140
pref = manager.get_db_pref(section="user", name="max_users")
132-
url = reverse("api:global-detail", kwargs={"pk": pref.preference.identifier()})
141+
url = reverse("api:global-detail",
142+
kwargs={"pk": pref.preference.identifier()})
133143
response = admin_client.get(url)
134144
assert response.status_code == 200
135145

@@ -141,7 +151,8 @@ def test_can_detail_preference(admin_client):
141151
def test_can_update_preference(admin_client):
142152
manager = registry.manager()
143153
pref = manager.get_db_pref(section="user", name="max_users")
144-
url = reverse("api:global-detail", kwargs={"pk": pref.preference.identifier()})
154+
url = reverse("api:global-detail",
155+
kwargs={"pk": pref.preference.identifier()})
145156
response = admin_client.patch(
146157
url, json.dumps({"value": 16}), content_type="application/json"
147158
)
@@ -155,7 +166,8 @@ def test_can_update_preference(admin_client):
155166
def test_can_update_decimal_preference(admin_client):
156167
manager = registry.manager()
157168
pref = manager.get_db_pref(section="type", name="cost")
158-
url = reverse("api:global-detail", kwargs={"pk": pref.preference.identifier()})
169+
url = reverse("api:global-detail",
170+
kwargs={"pk": pref.preference.identifier()})
159171
response = admin_client.patch(
160172
url, json.dumps({"value": "111.11"}), content_type="application/json"
161173
)
@@ -189,7 +201,8 @@ def test_can_update_multiple_preferences(admin_client):
189201
def test_update_preference_returns_validation_error(admin_client):
190202
manager = registry.manager()
191203
pref = manager.get_db_pref(section="user", name="max_users")
192-
url = reverse("api:global-detail", kwargs={"pk": pref.preference.identifier()})
204+
url = reverse("api:global-detail",
205+
kwargs={"pk": pref.preference.identifier()})
193206
response = admin_client.patch(
194207
url, json.dumps({"value": 1001}), content_type="application/json"
195208
)
@@ -200,7 +213,8 @@ def test_update_preference_returns_validation_error(admin_client):
200213
assert payload["value"] == ["Wrong value!"]
201214

202215

203-
def test_update_multiple_preferences_with_validation_errors_rollback(admin_client):
216+
def test_update_multiple_preferences_with_validation_errors_rollback(
217+
admin_client):
204218
manager = registry.manager()
205219
pref = manager.get_db_pref(section="user", name="max_users")
206220
url = reverse("api:global-bulk")
@@ -221,3 +235,69 @@ def test_update_multiple_preferences_with_validation_errors_rollback(admin_clien
221235

222236
assert pref1.value == pref1.preference.default
223237
assert pref2.value == pref2.preference.default
238+
239+
240+
def test_update_preference_send_signal(admin_client):
241+
manager = registry.manager()
242+
pref = manager.get_db_pref(section="user", name="max_users")
243+
244+
receiver = MagicMock()
245+
preference_updated.connect(receiver)
246+
247+
url = reverse("api:global-detail",
248+
kwargs={"pk": pref.preference.identifier()})
249+
response = admin_client.patch(
250+
url, json.dumps({"value": 16}), content_type="application/json"
251+
)
252+
assert response.status_code == 200
253+
assert receiver.call_count == 1
254+
call_args = receiver.call_args[1]
255+
assert {
256+
"sender": GlobalPreferenceSerializer,
257+
"section": "user",
258+
"name": "max_users",
259+
"old_value": 100,
260+
"new_value": 16,
261+
"instance": pref
262+
}.items() <= call_args.items()
263+
264+
265+
def test_update_multiple_preferences_send_signal(admin_client):
266+
manager = registry.manager()
267+
max_user_pref = manager.get_db_pref(section="user", name="max_users")
268+
registration_allowed_pref = manager.get_db_pref(section="user",
269+
name="registration_allowed")
270+
271+
receiver = MagicMock()
272+
preference_updated.connect(receiver)
273+
274+
url = reverse("api:global-bulk")
275+
276+
payload = {
277+
"user__max_users": 16,
278+
"user__registration_allowed": True,
279+
}
280+
response = admin_client.post(
281+
url, json.dumps(payload), content_type="application/json"
282+
)
283+
assert response.status_code == 200
284+
assert receiver.call_count == 2
285+
call_args = receiver.call_args_list[0][1]
286+
assert {
287+
"sender": GlobalPreferenceSerializer,
288+
"section": "user",
289+
"name": "max_users",
290+
"old_value": 100,
291+
"new_value": 16,
292+
"instance": max_user_pref
293+
}.items() <= call_args.items()
294+
295+
call_args = receiver.call_args_list[1][1]
296+
assert {
297+
"sender": GlobalPreferenceSerializer,
298+
"section": "user",
299+
"name": "registration_allowed",
300+
"old_value": False,
301+
"new_value": True,
302+
"instance": registration_allowed_pref
303+
}.items() <= call_args.items()

0 commit comments

Comments
 (0)