{"id":41141661,"url":"https://github.com/demux/drf-webhooks","last_synced_at":"2026-01-22T18:50:22.113Z","repository":{"id":71097262,"uuid":"592028751","full_name":"demux/drf-webhooks","owner":"demux","description":"Configurable Webhooks for DRF Serializers","archived":false,"fork":false,"pushed_at":"2023-04-04T12:29:43.000Z","size":181,"stargazers_count":1,"open_issues_count":9,"forks_count":0,"subscribers_count":1,"default_branch":"dev","last_synced_at":"2024-11-15T22:30:43.891Z","etag":null,"topics":["django","django-rest-framework","webhook","webhook-api","webhook-server","webhooks"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/demux.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-01-22T17:53:30.000Z","updated_at":"2023-02-26T11:25:10.000Z","dependencies_parsed_at":null,"dependency_job_id":"80f1ec14-ddd5-48aa-92ff-69d605bd7c02","html_url":"https://github.com/demux/drf-webhooks","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/demux/drf-webhooks","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/demux%2Fdrf-webhooks","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/demux%2Fdrf-webhooks/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/demux%2Fdrf-webhooks/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/demux%2Fdrf-webhooks/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/demux","download_url":"https://codeload.github.com/demux/drf-webhooks/tar.gz/refs/heads/dev","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/demux%2Fdrf-webhooks/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28668509,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-22T17:07:18.858Z","status":"ssl_error","status_checked_at":"2026-01-22T17:05:02.040Z","response_time":144,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["django","django-rest-framework","webhook","webhook-api","webhook-server","webhooks"],"created_at":"2026-01-22T18:50:21.335Z","updated_at":"2026-01-22T18:50:22.093Z","avatar_url":"https://github.com/demux.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Django Rest Framework - Webhooks\n**Configurable webhooks for DRF Serializers**\n\n## Goals:\n- [x] Use existing DRF Serializers from REST API to serialize data in webhooks\n    - [x] Consistent data formatting\n    - [x] Reusable OpenAPI schemas\n- [x] Configurable webhooks that simply work *(by way of django signals magic)* without the developer having to keep track of where to trigger them\n    - [x] Still allow for \"manual\" triggering of webhooks\n        - This is useful because signals aren't always triggered\n        - For example: `QuerySet.update` does not trigger signals\n- [x] Disable webhooks using context managers\n    - This can be useful when syncing large chunks of data\n    - or with a duplex sync (when two systems sync with each other) to avoid endless loops\n- [x] **Webhook Signal Session**\n    - [x] A context manager gathers all models signals and at the end of the session only triggers the resulting webhooks\n        - [x] If a model instance is both `created` and `deleted` within the session, then no webhook is sent for that model instance\n        - [x] If a model instance is `created` and then also `updated` within the session, then a `created` event is sent with the data from the last `updated` signal. Only one webhook even is sent\n        - [x] If a models instance is `updated` multiple times within the session, then only one webhook event is sent\n    - [x] Middleware wraps each request in **Webhook Signal Session** context\n        - **NOTE:** The developer will have to call the context manager in code that runs outside of requests (for example in celery tasks) manually\n- [x] Automatically determine which nested models need to be monitored for changes\n\n## Examples:\n\n```python\nfrom django.db import models\nfrom drf_webhooks import ModelSerializerWebhook, register_webhook\nfrom rest_framework import serializers\n\n\nclass MyModel(models.Model):\n    name = models.CharField(max_lenght=100)\n\n\nclass MyModelSerializer(serializers.ModelSerializer):\n    class Meta:\n        model = MyModel\n        fields = ['id', 'name']\n\n\n# Automatic:\nregister_webhook(MyModelSerializer)()\n\n# ---- OR ----\n# If you need more configuration:\n@register_webhook(MyModelSerializer)\nclass MyModelWebhook(ModelSerializerWebhook):\n    base_name = 'core.my_model'\n```\n\n# Documentation:\n\n## Quckstart:\n\n### Install `drf-webhooks`\n```bash\npoetry add drf-webhooks\n# ... or ...\npip install drf-webhooks\n```\n\n### Update `settings.py`:\n```python\nINSTALLED_APPS = [\n    # ...\n    'drf_webhooks',\n]\n\nMIDDLEWARE = [\n    # ...\n    'drf_webhooks.middleware.WebhooksMiddleware',\n]\n\n# This is required if you don't want your database to fill up with logs:\nCELERY_BEAT_SCHEDULE = {\n    'clean-webhook-log': {\n        'task': 'drf_webhooks.tasks.auto_clean_log',\n        'schedule': 60,\n        'options': {'expires': 10},\n    },\n}\n```\n\n### Create a new django app\nRecommended app name: `webhooks`\n\n```python\n# ----------------------------------------------------------------------\n#  apps.py\n# ----------------------------------------------------------------------\nfrom django.apps import AppConfig\n\n\nclass WebhooksAppConfig(AppConfig):\n    name = \"\u003cyour module name\u003e\"\n    label = \"webhooks\"\n\n\n# ----------------------------------------------------------------------\n#  models.py\n# ----------------------------------------------------------------------\nfrom django.contrib.auth import get_user_model\nfrom django.db import models\nfrom django.utils.translation import gettext_lazy as _\n\nfrom drf_webhooks.models import AbstractWebhook, AbstractWebhookLogEntry\n\n\nclass Webhook(AbstractWebhook):\n    # This can also be a group or an organization that the user belongs to:\n    owner = models.ForeignKey(get_user_model(), on_delete=models.CASCADE)\n\n    def __str__(self):\n        return 'id=%s, events=%s, owner=%s' % (\n            str(self.id),\n            ', '.join(self.events),\n            str(self.owner),\n        )\n\n\nclass WebhookLogEntry(AbstractWebhookLogEntry):\n    # This can also be a group or an organization that the user belongs to:\n    owner = models.ForeignKey(get_user_model(), on_delete=models.CASCADE)\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdemux%2Fdrf-webhooks","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdemux%2Fdrf-webhooks","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdemux%2Fdrf-webhooks/lists"}