django-webhook-subscriber 2.0.0__py3-none-any.whl → 2.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -8,7 +8,7 @@ from django.utils import timezone
8
8
  from django.utils.module_loading import import_string
9
9
 
10
10
  from .conf import rest_webhook_settings as settings
11
- from .serializers import serialize_webhook_instance
11
+ from .serializers import WebhookRawPayloadMixin, serialize_webhook_instance
12
12
  from .tasks import process_webhook_delivery_batch
13
13
  from .utils import (
14
14
  clear_content_type_cache,
@@ -184,14 +184,20 @@ class WebhookDeliveryProcessor:
184
184
  )
185
185
 
186
186
  # Build standard payload structure
187
- payload = {
188
- "pk": instance.pk,
189
- "event_signal": event_name,
190
- "source": f"{instance._meta.app_label}."
191
- f"{instance._meta.model_name}",
192
- "timestamp": timezone.now().isoformat(),
193
- "fields": fields_data,
194
- }
187
+ if serializer_class and issubclass(
188
+ serializer_class, WebhookRawPayloadMixin
189
+ ):
190
+ # Raw payload mixin - use fields data directly
191
+ payload = fields_data
192
+ else:
193
+ payload = {
194
+ "pk": instance.pk,
195
+ "event_signal": event_name,
196
+ "source": f"{instance._meta.app_label}."
197
+ f"{instance._meta.model_name}",
198
+ "timestamp": timezone.now().isoformat(),
199
+ "fields": fields_data,
200
+ }
195
201
 
196
202
  return payload
197
203
 
@@ -39,3 +39,16 @@ def serialize_webhook_instance(instance, field_serializer=None):
39
39
  serialized_data = serializer.data
40
40
  # Return the serialized data
41
41
  return serialized_data
42
+
43
+
44
+ class WebhookRawPayloadMixin:
45
+ """
46
+ Mixin to indicate that the webhook payload should be sent as raw data.
47
+
48
+ By default, the payload includes extra fields and the serialized
49
+ instance data goes inside a 'fields' key.
50
+ By having this mixin, the webhook payload will be just the
51
+ serialized instance data.
52
+ """
53
+
54
+ pass
@@ -220,6 +220,78 @@ class WebhookDeliveryProcessorTests(TestCase):
220
220
  self.assertIn("error", result)
221
221
  self.assertEqual(result["fields"], {})
222
222
 
223
+ @patch("django_webhook_subscriber.delivery.serialize_webhook_instance")
224
+ @patch("django_webhook_subscriber.delivery.import_string")
225
+ def test_generate_payload_with_raw_payload_mixin(
226
+ self, mock_import_string, mock_serialize
227
+ ):
228
+ """Test that WebhookRawPayloadMixin returns only serialized data."""
229
+ from rest_framework import serializers
230
+
231
+ from django_webhook_subscriber.serializers import (
232
+ WebhookRawPayloadMixin,
233
+ )
234
+
235
+ # Create a serializer class with WebhookRawPayloadMixin
236
+ class RawPayloadSerializer(
237
+ WebhookRawPayloadMixin, serializers.ModelSerializer
238
+ ):
239
+ class Meta:
240
+ model = models.WebhookDeliveryLog
241
+ fields = ["id", "payload"]
242
+
243
+ mock_import_string.return_value = RawPayloadSerializer
244
+ mock_serialize.return_value = {"id": 1, "payload": {"key": "value"}}
245
+
246
+ result = self.processor._generate_payload(
247
+ self.instance,
248
+ "created",
249
+ "some.path.RawPayloadSerializer",
250
+ )
251
+
252
+ # With WebhookRawPayloadMixin, the payload should be the serialized
253
+ # data directly, without metadata wrapper
254
+ self.assertEqual(result, {"id": 1, "payload": {"key": "value"}})
255
+ self.assertNotIn("pk", result)
256
+ self.assertNotIn("event_signal", result)
257
+ self.assertNotIn("source", result)
258
+ self.assertNotIn("timestamp", result)
259
+ self.assertNotIn("fields", result)
260
+
261
+ @patch("django_webhook_subscriber.delivery.serialize_webhook_instance")
262
+ @patch("django_webhook_subscriber.delivery.import_string")
263
+ def test_generate_payload_without_raw_payload_mixin(
264
+ self, mock_import_string, mock_serialize
265
+ ):
266
+ """Test that regular serializers return payload with metadata."""
267
+ from rest_framework import serializers
268
+
269
+ # Create a regular serializer without WebhookRawPayloadMixin
270
+ class RegularSerializer(serializers.ModelSerializer):
271
+ class Meta:
272
+ model = models.WebhookDeliveryLog
273
+ fields = ["id", "payload"]
274
+
275
+ mock_import_string.return_value = RegularSerializer
276
+ mock_serialize.return_value = {"id": 1, "payload": {"key": "value"}}
277
+
278
+ result = self.processor._generate_payload(
279
+ self.instance,
280
+ "created",
281
+ "some.path.RegularSerializer",
282
+ )
283
+
284
+ # Without WebhookRawPayloadMixin, the payload should include metadata
285
+ self.assertEqual(result["pk"], 1)
286
+ self.assertEqual(result["event_signal"], "created")
287
+ self.assertEqual(
288
+ result["source"], "django_webhook_subscriber.webhookdeliverylog"
289
+ )
290
+ self.assertIn("timestamp", result)
291
+ self.assertEqual(
292
+ result["fields"], {"id": 1, "payload": {"key": "value"}}
293
+ )
294
+
223
295
  def test_deliver_webhooks_on_no_subscriptions(self):
224
296
  result = self.processor._deliver_webhooks([])
225
297
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: django-webhook-subscriber
3
- Version: 2.0.0
3
+ Version: 2.1.0
4
4
  Summary: A Django package designed to handle webhook creation, management, and delivery.
5
5
  Author-email: 42 Portugal <root@42porto.com>
6
6
  Classifier: Environment :: Web Environment
@@ -172,6 +172,53 @@ subscriber.serializer_class = "myapp.serializers.UserWebhookSerializer"
172
172
  subscriber.save()
173
173
  ```
174
174
 
175
+ ### 4. Raw Payload (No Metadata Wrapper)
176
+
177
+ By default, webhook payloads include metadata and the serialized data is nested inside a `fields` key:
178
+
179
+ ```json
180
+ {
181
+ "pk": 1,
182
+ "event_signal": "created",
183
+ "source": "auth.user",
184
+ "timestamp": "2026-02-05T10:30:00Z",
185
+ "fields": {
186
+ "id": 1,
187
+ "name": "John Doe",
188
+ "email": "john@example.com"
189
+ }
190
+ }
191
+ ```
192
+
193
+ If you prefer a raw payload containing only the serialized data (without the metadata wrapper), use the `WebhookRawPayloadMixin`:
194
+
195
+ ```python
196
+ from rest_framework import serializers
197
+ from django.contrib.auth import get_user_model
198
+ from django_webhook_subscriber.serializers import WebhookRawPayloadMixin
199
+
200
+ User = get_user_model()
201
+
202
+ class UserRawWebhookSerializer(WebhookRawPayloadMixin, serializers.ModelSerializer):
203
+ class Meta:
204
+ model = User
205
+ fields = ["id", "name", "email"]
206
+
207
+ # Update subscriber to use the raw payload serializer
208
+ subscriber.serializer_class = "myapp.serializers.UserRawWebhookSerializer"
209
+ subscriber.save()
210
+ ```
211
+
212
+ With `WebhookRawPayloadMixin`, the webhook payload will be just the serialized data:
213
+
214
+ ```json
215
+ {
216
+ "id": 1,
217
+ "name": "John Doe",
218
+ "email": "john@example.com"
219
+ }
220
+ ```
221
+
175
222
  ## Configuration
176
223
 
177
224
  Configure the package in your Django settings:
@@ -632,6 +679,7 @@ Set up cron jobs for maintenance:
632
679
  ```
633
680
 
634
681
  3. **Monitor delivery performance:**
682
+
635
683
  ```bash
636
684
  # Regular performance testing
637
685
  python manage.py webhook_performance_test --model=myapp.User --event=test --object-count=10
@@ -2,11 +2,11 @@ django_webhook_subscriber/__init__.py,sha256=t0izlsRXKHd46fRIwhDv8Cd59tb7MqAQ7DW
2
2
  django_webhook_subscriber/admin.py,sha256=BGFV-1-wymm_qUsOlG0HBUY3rmAqKH59PbKaFEtAEI4,30100
3
3
  django_webhook_subscriber/apps.py,sha256=U6GLuMB2xhtvUzn2IsK6rjaxN73LU3fvDoGGO1IZIr4,170
4
4
  django_webhook_subscriber/conf.py,sha256=0lFW2L_s_85UIszXnUnnMCdb0iy99WnenPWeixonf-I,1759
5
- django_webhook_subscriber/delivery.py,sha256=mjNtIMeVsXoVnWfEBmW8WsVDDPYfKcz8HIMkJ40PHjQ,15207
5
+ django_webhook_subscriber/delivery.py,sha256=VQg2x9lQb49mNRKFK6-INTWaAh6O-IlLwp9nHIzv1vM,15502
6
6
  django_webhook_subscriber/http.py,sha256=0CoK1OMm7lCIJ3zzpNH3cdVuIgDnAB4KUqLRM_KRGQs,1191
7
7
  django_webhook_subscriber/managers.py,sha256=w2QZCYs858XMlcI-WSZJ0H8vN_IzpTvu5_H3bmiy7zM,2322
8
8
  django_webhook_subscriber/models.py,sha256=IdG0eBE3JPUmPLWqpR62GLtA4xVF8caIU92ourgRzVk,11528
9
- django_webhook_subscriber/serializers.py,sha256=9QHzlTXvk-PibMSoztaGsDoZkVhCXJkuQMDDTPCKjak,1416
9
+ django_webhook_subscriber/serializers.py,sha256=1e1rqLLd9v3qiZwKMHJsO4TakF5FXfVc8lqk7QNt7KU,1758
10
10
  django_webhook_subscriber/tasks.py,sha256=jlE8Mdor387gcWfHlrMe8OGoegjt2xn8gsVVL8LkHDY,14269
11
11
  django_webhook_subscriber/utils.py,sha256=SdogR0VmeMMl7tgl-DD5_4yP7vt3OcgI8IpghoCIVXQ,2950
12
12
  django_webhook_subscriber/validators.py,sha256=_qlBi0rS3DaW3jKRhdpnfHzuqupqwaWtiNuZAWpIAkU,1848
@@ -24,15 +24,15 @@ django_webhook_subscriber/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeu
24
24
  django_webhook_subscriber/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
25
25
  django_webhook_subscriber/tests/factories.py,sha256=z3fXJqt_3csAFrvM5qdKwzsVu0v_e72racLvMgejEKA,1277
26
26
  django_webhook_subscriber/tests/settings.py,sha256=jBy9X7QhmoQ9hnaJk4WDGWXqpRydpHlrROaXU5t7KZI,825
27
- django_webhook_subscriber/tests/test_delivery.py,sha256=W7JrNurpTb0TA0JDyumd6UMytaQYPJ6DohS0pDNjyJw,18380
27
+ django_webhook_subscriber/tests/test_delivery.py,sha256=XWc7BTCXALCXn9uvqFlaQhbHlT1tyAcvQECtajeBfnY,21231
28
28
  django_webhook_subscriber/tests/test_http.py,sha256=-zBNRjpYxBDCC5NvWfdYc36aFdzCwN-1p8yuQsLGfz8,1262
29
29
  django_webhook_subscriber/tests/test_managers.py,sha256=z_c49z0UjkAnldXy-KU_XoECC66dr7orE77_xFvnM4A,3062
30
30
  django_webhook_subscriber/tests/test_models.py,sha256=RHE14IuaMtthiaRZ8g4h2EZ4VilWOrs9UrkArDbvcDg,15209
31
31
  django_webhook_subscriber/tests/test_serializers.py,sha256=UuN-cDDmsu8ZFB-aPesffT74Ck6uIuDo9ehkq8y43Mw,1831
32
32
  django_webhook_subscriber/tests/test_tasks.py,sha256=wcYlYqrRC9G3C4leEAKrt7x7D1uhlqx9mfwkfQYnb8c,20622
33
33
  django_webhook_subscriber/tests/test_utils.py,sha256=zFXDjr81wB8emeJKNjlwA8ezfJTfCMSw46-S2dB_fO0,4279
34
- django_webhook_subscriber-2.0.0.dist-info/licenses/LICENSE,sha256=Cqe_H97kNjzh70ZIee47TV5t0GQyath_iH2i0Yp47SU,1064
35
- django_webhook_subscriber-2.0.0.dist-info/METADATA,sha256=tzvYtcH4spdVL7BVftgDOBm_udSa3A3R--NFNcgdxlE,17789
36
- django_webhook_subscriber-2.0.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
37
- django_webhook_subscriber-2.0.0.dist-info/top_level.txt,sha256=t2_XjlYcTMLR9OfBGdsW0xucs3OeRWrJ7ypETMXqrvw,26
38
- django_webhook_subscriber-2.0.0.dist-info/RECORD,,
34
+ django_webhook_subscriber-2.1.0.dist-info/licenses/LICENSE,sha256=Cqe_H97kNjzh70ZIee47TV5t0GQyath_iH2i0Yp47SU,1064
35
+ django_webhook_subscriber-2.1.0.dist-info/METADATA,sha256=pAzJd6R07F-PNfZSM0HbZctK9sL1IIUafynDfVf09r4,18982
36
+ django_webhook_subscriber-2.1.0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
37
+ django_webhook_subscriber-2.1.0.dist-info/top_level.txt,sha256=t2_XjlYcTMLR9OfBGdsW0xucs3OeRWrJ7ypETMXqrvw,26
38
+ django_webhook_subscriber-2.1.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.9.0)
2
+ Generator: setuptools (80.10.2)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5