Skip to content

Fix #310 The preference_updated signal is now triggered when using the REST API #311

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jan 10, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions docs/react_to_updates.rst
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,15 @@ of the signal, which are:
* ``name`` - the name of the changed preference
* ``old_value`` - the value of the preference before changing
* ``new_value`` - the value assigned to the preference after the change

* ``instance`` - the preference Model instance
An example that just prints a message that the preference was changed is
below.

.. code-block:: python

# yourapp/util.py

def notify_on_preference_update(sender, section, name, old_value, new_value, **kwargs):
def notify_on_preference_update(sender, section, name, old_value, new_value, instance, **kwargs):
print("Preference {} in section {} changed from {} to {}".format(
name, section, old, new))

Expand Down
12 changes: 11 additions & 1 deletion dynamic_preferences/api/serializers.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from rest_framework import serializers
from dynamic_preferences.models import GlobalPreferenceModel

from dynamic_preferences.signals import preference_updated


class PreferenceValueField(serializers.Field):
Expand Down Expand Up @@ -62,8 +63,17 @@ def validate_value(self, value):
return value

def update(self, instance, validated_data):
old_value = instance.value
instance.value = validated_data["value"]
instance.save()
preference_updated.send(
sender=self.__class__,
section=instance.section,
name=instance.name,
old_value=old_value,
new_value=validated_data["value"],
instance=instance
)
return instance


Expand Down
1 change: 1 addition & 0 deletions dynamic_preferences/managers.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ def update_db_pref(self, section, name, value):
name=name,
old_value=old_value,
new_value=value,
instance=db_pref
)
except self.model.DoesNotExist:
return self.create_db_pref(section, name, value)
Expand Down
3 changes: 3 additions & 0 deletions tests/test_preferences.py
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,8 @@ class P(StringPreference):
def test_preferences_manager_signal(db):
global_preferences = global_preferences_registry.manager()
global_preferences["no_section"] = False
pref = global_preferences.get_db_pref(name="no_section", section=None)

receiver = MagicMock()
preference_updated.connect(receiver)
global_preferences["no_section"] = True
Expand All @@ -203,4 +205,5 @@ def test_preferences_manager_signal(db):
"name": "no_section",
"old_value": False,
"new_value": True,
"instance": pref
}.items() <= call_args.items()
98 changes: 89 additions & 9 deletions tests/test_rest_framework.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,23 @@
import json

from decimal import Decimal

from django.urls import reverse

from dynamic_preferences.registries import global_preferences_registry as registry
from dynamic_preferences.api import serializers
from dynamic_preferences.api.serializers import GlobalPreferenceSerializer
from dynamic_preferences.registries import \
global_preferences_registry as registry
from dynamic_preferences.signals import preference_updated
from dynamic_preferences.users.registries import (
user_preferences_registry as user_registry,
)
from dynamic_preferences.api import serializers
from dynamic_preferences.users.serializers import UserPreferenceSerializer

try:
from unittest.mock import MagicMock
except ImportError:
from mock import MagicMock


def test_can_serialize_preference(db):
manager = registry.manager()
Expand Down Expand Up @@ -78,7 +86,8 @@ def test_serializer_includes_additional_data_if_any(fake_user):
pref = manager.get_db_pref(section="user", name="favorite_vegetable")

serializer = UserPreferenceSerializer(pref)
assert serializer.data["additional_data"]["choices"] == pref.preference.choices
assert serializer.data["additional_data"][
"choices"] == pref.preference.choices


def test_global_preference_list_requires_permission(db, client):
Expand Down Expand Up @@ -129,7 +138,8 @@ def test_can_list_preferences_with_section_filter(admin_client):
def test_can_detail_preference(admin_client):
manager = registry.manager()
pref = manager.get_db_pref(section="user", name="max_users")
url = reverse("api:global-detail", kwargs={"pk": pref.preference.identifier()})
url = reverse("api:global-detail",
kwargs={"pk": pref.preference.identifier()})
response = admin_client.get(url)
assert response.status_code == 200

Expand All @@ -141,7 +151,8 @@ def test_can_detail_preference(admin_client):
def test_can_update_preference(admin_client):
manager = registry.manager()
pref = manager.get_db_pref(section="user", name="max_users")
url = reverse("api:global-detail", kwargs={"pk": pref.preference.identifier()})
url = reverse("api:global-detail",
kwargs={"pk": pref.preference.identifier()})
response = admin_client.patch(
url, json.dumps({"value": 16}), content_type="application/json"
)
Expand All @@ -155,7 +166,8 @@ def test_can_update_preference(admin_client):
def test_can_update_decimal_preference(admin_client):
manager = registry.manager()
pref = manager.get_db_pref(section="type", name="cost")
url = reverse("api:global-detail", kwargs={"pk": pref.preference.identifier()})
url = reverse("api:global-detail",
kwargs={"pk": pref.preference.identifier()})
response = admin_client.patch(
url, json.dumps({"value": "111.11"}), content_type="application/json"
)
Expand Down Expand Up @@ -189,7 +201,8 @@ def test_can_update_multiple_preferences(admin_client):
def test_update_preference_returns_validation_error(admin_client):
manager = registry.manager()
pref = manager.get_db_pref(section="user", name="max_users")
url = reverse("api:global-detail", kwargs={"pk": pref.preference.identifier()})
url = reverse("api:global-detail",
kwargs={"pk": pref.preference.identifier()})
response = admin_client.patch(
url, json.dumps({"value": 1001}), content_type="application/json"
)
Expand All @@ -200,7 +213,8 @@ def test_update_preference_returns_validation_error(admin_client):
assert payload["value"] == ["Wrong value!"]


def test_update_multiple_preferences_with_validation_errors_rollback(admin_client):
def test_update_multiple_preferences_with_validation_errors_rollback(
admin_client):
manager = registry.manager()
pref = manager.get_db_pref(section="user", name="max_users")
url = reverse("api:global-bulk")
Expand All @@ -221,3 +235,69 @@ def test_update_multiple_preferences_with_validation_errors_rollback(admin_clien

assert pref1.value == pref1.preference.default
assert pref2.value == pref2.preference.default


def test_update_preference_send_signal(admin_client):
manager = registry.manager()
pref = manager.get_db_pref(section="user", name="max_users")

receiver = MagicMock()
preference_updated.connect(receiver)

url = reverse("api:global-detail",
kwargs={"pk": pref.preference.identifier()})
response = admin_client.patch(
url, json.dumps({"value": 16}), content_type="application/json"
)
assert response.status_code == 200
assert receiver.call_count == 1
call_args = receiver.call_args[1]
assert {
"sender": GlobalPreferenceSerializer,
"section": "user",
"name": "max_users",
"old_value": 100,
"new_value": 16,
"instance": pref
}.items() <= call_args.items()


def test_update_multiple_preferences_send_signal(admin_client):
manager = registry.manager()
max_user_pref = manager.get_db_pref(section="user", name="max_users")
registration_allowed_pref = manager.get_db_pref(section="user",
name="registration_allowed")

receiver = MagicMock()
preference_updated.connect(receiver)

url = reverse("api:global-bulk")

payload = {
"user__max_users": 16,
"user__registration_allowed": True,
}
response = admin_client.post(
url, json.dumps(payload), content_type="application/json"
)
assert response.status_code == 200
assert receiver.call_count == 2
call_args = receiver.call_args_list[0][1]
assert {
"sender": GlobalPreferenceSerializer,
"section": "user",
"name": "max_users",
"old_value": 100,
"new_value": 16,
"instance": max_user_pref
}.items() <= call_args.items()

call_args = receiver.call_args_list[1][1]
assert {
"sender": GlobalPreferenceSerializer,
"section": "user",
"name": "registration_allowed",
"old_value": False,
"new_value": True,
"instance": registration_allowed_pref
}.items() <= call_args.items()