Add example project (#215)

* add example project

* format

* fix format
This commit is contained in:
Stan Triepels
2024-09-08 03:13:49 +02:00
committed by GitHub
parent af505e8d70
commit 2191897825
13 changed files with 272 additions and 15 deletions

View File

@@ -1,4 +1,4 @@
FROM python:3.9 FROM python:3.12
ENV PYTHONUNBUFFERED 1 ENV PYTHONUNBUFFERED 1
RUN mkdir -p /app RUN mkdir -p /app

12
Makefile Normal file
View File

@@ -0,0 +1,12 @@
dev:
docker compose -f web-docker-compose.yaml up
test:
docker-compose -f test-services-docker-compose.yaml run --rm django-q2 poetry run pytest
createsuperuser:
docker compose -f web-docker-compose.yaml run --rm web python manage.py createsuperuser
format:
docker compose -f test-services-docker-compose.yaml run --rm django-q2 poetry run ruff format .
docker compose -f test-services-docker-compose.yaml run --rm django-q2 poetry run ruff check . --fix

View File

@@ -197,6 +197,24 @@ Admin page or directly from your code:
For more info check the `Schedules <https://django-q2.readthedocs.org/en/latest/schedules.html>`__ documentation. For more info check the `Schedules <https://django-q2.readthedocs.org/en/latest/schedules.html>`__ documentation.
Development
~~~~~~~
There is an example project that you can use to develop with. Docker (compose) is being used to set everything up.
Please note that you will have to restart the django-q container when changes have been made to tasks or django-q.
You can start the example project with:
.. code:: bash
make dev
Create a superuser with:
.. code:: bash
make createsuperuser
Testing Testing
~~~~~~~ ~~~~~~~
@@ -204,7 +222,7 @@ Running tests is easy with docker compose, it will also start the necessary data
.. code:: bash .. code:: bash
docker-compose -f test-services-docker-compose.yaml run --rm django-q2 poetry run pytest make test
Locale Locale
~~~~~~ ~~~~~~
@@ -212,12 +230,6 @@ Locale
Currently available in English, German, Turkish, and French. Currently available in English, German, Turkish, and French.
Translation pull requests are always welcome. Translation pull requests are always welcome.
Todo
~~~~
- Better tests and coverage
- Less dependencies?
Acknowledgements Acknowledgements
~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~

View File

@@ -21,7 +21,14 @@ from django.utils.translation import gettext_lazy as _
# Local # Local
from django_q.brokers import Broker, get_broker from django_q.brokers import Broker, get_broker
from django_q.conf import Conf, get_ppid, logger, psutil, setproctitle, prometheus_multiprocess from django_q.conf import (
Conf,
get_ppid,
logger,
prometheus_multiprocess,
psutil,
setproctitle,
)
from django_q.humanhash import humanize from django_q.humanhash import humanize
from django_q.monitor import monitor from django_q.monitor import monitor
from django_q.pusher import pusher from django_q.pusher import pusher

View File

@@ -1,4 +1,3 @@
version: "3.0"
services: services:
docs: docs:
container_name: djangoq2-docs container_name: djangoq2-docs

View File

16
exampleproject/asgi.py Normal file
View File

@@ -0,0 +1,16 @@
"""
ASGI config for exampleproject project.
It exposes the ASGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/5.1/howto/deployment/asgi/
"""
import os
from django.core.asgi import get_asgi_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "exampleproject.settings")
application = get_asgi_application()

134
exampleproject/settings.py Normal file
View File

@@ -0,0 +1,134 @@
"""
Django settings for exampleproject project.
Generated by 'django-admin startproject' using Django 5.1.1.
For more information on this file, see
https://docs.djangoproject.com/en/5.1/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/5.1/ref/settings/
"""
from pathlib import Path
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/5.1/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = "django-insecure-)oouh93bjg+c=b!l5-*w)7et1l+!3nmp223rr^1r4v#jn&ow3f"
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = ["*"]
# Application definition
INSTALLED_APPS = [
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
"django_q",
]
MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
"django.contrib.messages.middleware.MessageMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
]
ROOT_URLCONF = "exampleproject.urls"
TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [],
"APP_DIRS": True,
"OPTIONS": {
"context_processors": [
"django.template.context_processors.debug",
"django.template.context_processors.request",
"django.contrib.auth.context_processors.auth",
"django.contrib.messages.context_processors.messages",
],
},
},
]
WSGI_APPLICATION = "exampleproject.wsgi.application"
# Database
# https://docs.djangoproject.com/en/5.1/ref/settings/#databases
DATABASES = {
"default": {
"ENGINE": "django.db.backends.sqlite3",
"NAME": BASE_DIR / "db.sqlite3",
}
}
# Password validation
# https://docs.djangoproject.com/en/5.1/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
},
{
"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
},
{
"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
},
{
"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
},
]
# Internationalization
# https://docs.djangoproject.com/en/5.1/topics/i18n/
LANGUAGE_CODE = "en-us"
TIME_ZONE = "UTC"
USE_I18N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/5.1/howto/static-files/
STATIC_URL = "static/"
# Default primary key field type
# https://docs.djangoproject.com/en/5.1/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
Q_CLUSTER = {
"name": "DjangORM",
"workers": 4,
"timeout": 90,
"retry": 120,
"queue_limit": 50,
"bulk": 10,
"orm": "default",
}

27
exampleproject/urls.py Normal file
View File

@@ -0,0 +1,27 @@
"""
URL configuration for exampleproject project.
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/5.1/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path
from exampleproject import views
urlpatterns = [
path("admin/", admin.site.urls),
path("new_task/", views.add_task, name="add_task"),
path("result/<slug:task_id>/", views.get_result, name="get_result"),
]

31
exampleproject/views.py Normal file
View File

@@ -0,0 +1,31 @@
import time
from django.http import HttpResponse
from django.urls import reverse
from django_q import tasks
# internal function to be called with django_q
def new_task(run_for_minutes):
print("Task started")
time.sleep(run_for_minutes)
print("Task done")
return True
def add_task(request):
task_id = tasks.async_task(new_task, 5)
result_url = reverse("get_result", args=[task_id])
return HttpResponse(
f"Added async task with <a href='{result_url}'>Go to results</a>"
)
def get_result(request, task_id):
task = tasks.fetch(task_id)
if not task:
msg = "Task running... please refresh after some time"
else:
msg = f"Async task result: {task.result}"
return HttpResponse(msg)

16
exampleproject/wsgi.py Normal file
View File

@@ -0,0 +1,16 @@
"""
WSGI config for exampleproject project.
It exposes the WSGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/5.1/howto/deployment/wsgi/
"""
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "exampleproject.settings")
application = get_wsgi_application()

View File

@@ -1,5 +1,3 @@
version: '3'
services: services:
redis: redis:
image: redis:latest image: redis:latest

View File

@@ -1,11 +1,16 @@
version: '3'
services: services:
web: web:
restart: always restart: always
command: python manage.py runserver 0.0.0.0:8000 command: bash -c "python manage.py migrate && python manage.py runserver 0.0.0.0:8000"
ports: ports:
- "127.0.0.1:8000:8000" - "127.0.0.1:8000:8000"
build: . build: .
volumes: volumes:
- .:/app - .:/app
django-q:
restart: always
command: bash -c "python manage.py migrate && python manage.py qcluster"
build: .
volumes:
- .:/app