Skip to content

Commit

Permalink
Added example django project, minor config changes
Browse files Browse the repository at this point in the history
  • Loading branch information
jmitchel3 committed Dec 22, 2024
1 parent 49a2cd9 commit cfcc398
Show file tree
Hide file tree
Showing 31 changed files with 6,227 additions and 20 deletions.
9 changes: 9 additions & 0 deletions .env.sample
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# required for qstash-py
QSTASH_TOKEN="your_token"
QSTASH_CURRENT_SIGNING_KEY="your_current_signing_key"
QSTASH_NEXT_SIGNING_KEY="your_next_signing_key"

# required for django-qstash
DJANGO_QSTASH_DOMAIN="http://example.com"
DJANGO_QSTASH_WEBHOOK_PATH="/qstash/webhook/"
DJANGO_QSTASH_FORCE_HTTPS=False
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
example/

.DS_Store

Expand Down
57 changes: 53 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,66 @@
# django-qstash
# Django QStash `pip install django-qstash`

A skeleton Python package demonstrating how to set up and publish a Django-related library to PyPI.
A drop-in replacement for Celery's shared_task leveraging Upstash QStash for a truly serverless Django application to run background tasks asynchronously from the request/response cycle.

## Installation

```bash
pip install django-qstash
```

Depends on:

- [Python 3.10+](https://www.python.org/)
- [Django 5+](https://docs.djangoproject.com/)
- [qstash-py](https://github.com/upstash/qstash-py)

## Usage

```python
from django_qstash import hello_world
# from celery import shared_task
from django_qstash import shared_task

@shared_task
def math_add_task(a, b, save_to_file=False):
logger.info(f"Adding {a} and {b}")
if save_to_file:
with open("math-add-result.txt", "w") as f:
f.write(f"{a} + {b} = {a + b}")
return a + b
```

```python
math_add_task.apply_async(args=(12, 454), save_to_file=True)

hello_world()
# or

math_add_task.delay(12, 454, save_to_file=True)
```


## Configuration

### Environment variables


```python
QSTASH_TOKEN="your_token"
QSTASH_CURRENT_SIGNING_KEY="your_current_signing_key"
QSTASH_NEXT_SIGNING_KEY="your_next_signing_key"

# required for django-qstash
DJANGO_QSTASH_DOMAIN="https://example.com"
DJANGO_QSTASH_WEBHOOK_PATH="/qstash/webhook/"
```



`DJANGO_QSTASH_DOMAIN`: Must be a valid and publicly accessible domain. For example `https://djangoqstash.net`

In development mode, we recommend using a tunnel like [Cloudflare Tunnels](https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/) with a domain name you control. You can also consider [ngrok](https://ngrok.com/).


`DJANGO_QSTASH_WEBHOOK_PATH`: The path where QStash will send webhooks to your Django application. Defaults to `/qstash/webhook/`


`DJANGO_QSTASH_FORCE_HTTPS`: Whether to force HTTPS for the webhook. Defaults to `True`.
1 change: 1 addition & 0 deletions example/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/venv/
23 changes: 23 additions & 0 deletions example/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
Example Django Application
===================

Use Python 3.13 to set up and run with these commands:

```
echo "QSTASH_TOKEN=your_token" >> .env
echo "QSTASH_CALLBACK_URL=your_callback_url" >> .env
```

```bash
python3 -m venv venv
source venv/bin/activate
python -m pip install -r requirements.txt -e ..
DEBUG=1 python manage.py runserver
```

Open it at http://127.0.0.1:8000/ .

Browse the individual examples, and take them apart!

In your browser’s devtools, you can read the htmx `debug log <https://htmx.org/extensions/debug/>`__ in your browser’s console, and see the requests made in the network tab.
In the source code, check out the HTML comments via “view source” or templates, and the view code in ``example/views.py``.
Empty file added example/example/__init__.py
Empty file.
8 changes: 8 additions & 0 deletions example/example/context_processors.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from __future__ import annotations

from django.conf import settings
from django.http import HttpRequest


def debug(request: HttpRequest) -> dict[str, str]:
return {"DEBUG": settings.DEBUG}
59 changes: 59 additions & 0 deletions example/example/settings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
from __future__ import annotations

import os
from pathlib import Path
from typing import Any

from decouple import config
from django.core.management.utils import get_random_secret_key

BASE_DIR = Path(__file__).parent

DEBUG = os.environ.get("DEBUG", "") == "1"

SECRET_KEY = get_random_secret_key()

QSTASH_TOKEN = config("QSTASH_TOKEN")
QSTASH_CURRENT_SIGNING_KEY = config("QSTASH_CURRENT_SIGNING_KEY")
QSTASH_NEXT_SIGNING_KEY = config("QSTASH_NEXT_SIGNING_KEY")

DJANGO_QSTASH_DOMAIN = config("DJANGO_QSTASH_DOMAIN")
DJANGO_QSTASH_WEBHOOK_PATH = config(
"DJANGO_QSTASH_WEBHOOK_PATH", default="/qstash/webhook/"
)
# Dangerous: disable host header validation
ALLOWED_HOSTS = ["*"]

INSTALLED_APPS = [
"example",
"django_qstash",
"django.contrib.staticfiles",
]

MIDDLEWARE = [
"django.middleware.csrf.CsrfViewMiddleware",
]

ROOT_URLCONF = "example.urls"

DATABASES: dict[str, dict[str, Any]] = {}

TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [BASE_DIR / "templates"],
"APP_DIRS": True,
"OPTIONS": {
"context_processors": [
"django.template.context_processors.request",
"example.context_processors.debug",
]
},
}
]

USE_TZ = True


STATIC_URL = "/static/"
STATICFILES_DIRS = [BASE_DIR / "static"]
11 changes: 11 additions & 0 deletions example/example/static/ext/debug.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
htmx.defineExtension('debug', {
onEvent: function(name, evt) {
if (console.debug) {
console.debug(name, evt)
} else if (console) {
console.log('DEBUG:', name, evt)
} else {
throw new Error('NO CONSOLE SUPPORTED')
}
}
})
37 changes: 37 additions & 0 deletions example/example/static/ext/event-header.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
(function() {
function stringifyEvent(event) {
var obj = {}
for (var key in event) {
obj[key] = event[key]
}
return JSON.stringify(obj, function(key, value) {
if (value instanceof Node) {
var nodeRep = value.tagName
if (nodeRep) {
nodeRep = nodeRep.toLowerCase()
if (value.id) {
nodeRep += '#' + value.id
}
if (value.classList && value.classList.length) {
nodeRep += '.' + value.classList.toString().replace(' ', '.')
}
return nodeRep
} else {
return 'Node'
}
}
if (value instanceof Window) return 'Window'
return value
})
}

htmx.defineExtension('event-header', {
onEvent: function(name, evt) {
if (name === 'htmx:configRequest') {
if (evt.detail.triggeringEvent) {
evt.detail.headers['Triggering-Event'] = stringifyEvent(evt.detail.triggeringEvent)
}
}
}
})
})()
Loading

0 comments on commit cfcc398

Please sign in to comment.