django-tasks-local-db 0.1.0__tar.gz

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.
@@ -0,0 +1,79 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Forest Gregg
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
23
+ ---
24
+
25
+ This project incorporates code from the following projects:
26
+
27
+ ## django-tasks-local
28
+
29
+ MIT License
30
+
31
+ Copyright (c) 2026 Lincoln Loop
32
+
33
+ Permission is hereby granted, free of charge, to any person obtaining a copy
34
+ of this software and associated documentation files (the "Software"), to deal
35
+ in the Software without restriction, including without limitation the rights
36
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
37
+ copies of the Software, and to permit persons to whom the Software is
38
+ furnished to do so, subject to the following conditions:
39
+
40
+ The above copyright notice and this permission notice shall be included in all
41
+ copies or substantial portions of the Software.
42
+
43
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
44
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
45
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
46
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
47
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
48
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
49
+ SOFTWARE.
50
+
51
+ ## django-tasks-db
52
+
53
+ Copyright (c) Jake Howard and individual contributors.
54
+ All rights reserved.
55
+
56
+ Redistribution and use in source and binary forms, with or without modification,
57
+ are permitted provided that the following conditions are met:
58
+
59
+ 1. Redistributions of source code must retain the above copyright notice,
60
+ this list of conditions and the following disclaimer.
61
+
62
+ 2. Redistributions in binary form must reproduce the above copyright
63
+ notice, this list of conditions and the following disclaimer in the
64
+ documentation and/or other materials provided with the distribution.
65
+
66
+ 3. Neither the name of the copyright holder nor the names of its
67
+ contributors may be used to endorse or promote products derived from
68
+ this software without specific prior written permission.
69
+
70
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
71
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
72
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
73
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
74
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
75
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
76
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
77
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
78
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
79
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,53 @@
1
+ Metadata-Version: 2.4
2
+ Name: django-tasks-local-db
3
+ Version: 0.1.0
4
+ Summary: Django Tasks backend combining in-process thread pool execution with database persistence
5
+ License-Expression: MIT
6
+ Requires-Python: >=3.12
7
+ Requires-Dist: django>=6.0
8
+ Provides-Extra: dev
9
+ Requires-Dist: pytest; extra == "dev"
10
+ Requires-Dist: pytest-django; extra == "dev"
11
+ Description-Content-Type: text/markdown
12
+
13
+ # django-tasks-local-db
14
+
15
+ A [Django Tasks](https://docs.djangoproject.com/en/6.0/topics/tasks/) backend that combines in-process thread pool execution with database persistence. Tasks run in your web process without a separate worker, while results are durably stored in the database.
16
+
17
+ This project is a remix of [django-tasks-local](https://github.com/lincolnloop/django-tasks-local) and [django-tasks-db](https://github.com/RealOrangeOne/django-tasks-db). It takes the in-process executor approach from django-tasks-local and adds DB-backed result storage from django-tasks-db.
18
+
19
+ ## How it works
20
+
21
+ - `enqueue()` writes a task row to the database, then submits it to an in-process thread pool
22
+ - On completion, the DB row is updated with the result or error
23
+ - On restart, orphaned tasks are recovered from the database and resubmitted
24
+
25
+ ## Installation
26
+
27
+ ```bash
28
+ pip install django-tasks-local-db
29
+ ```
30
+
31
+ ## Configuration
32
+
33
+ ```python
34
+ INSTALLED_APPS = [
35
+ # ...
36
+ "django_tasks_local_db",
37
+ ]
38
+
39
+ TASKS = {
40
+ "default": {
41
+ "BACKEND": "django_tasks_local_db.LocalDBBackend",
42
+ "OPTIONS": {
43
+ "MAX_WORKERS": 4,
44
+ },
45
+ }
46
+ }
47
+ ```
48
+
49
+ Then run migrations:
50
+
51
+ ```bash
52
+ python manage.py migrate django_tasks_local_db
53
+ ```
@@ -0,0 +1,41 @@
1
+ # django-tasks-local-db
2
+
3
+ A [Django Tasks](https://docs.djangoproject.com/en/6.0/topics/tasks/) backend that combines in-process thread pool execution with database persistence. Tasks run in your web process without a separate worker, while results are durably stored in the database.
4
+
5
+ This project is a remix of [django-tasks-local](https://github.com/lincolnloop/django-tasks-local) and [django-tasks-db](https://github.com/RealOrangeOne/django-tasks-db). It takes the in-process executor approach from django-tasks-local and adds DB-backed result storage from django-tasks-db.
6
+
7
+ ## How it works
8
+
9
+ - `enqueue()` writes a task row to the database, then submits it to an in-process thread pool
10
+ - On completion, the DB row is updated with the result or error
11
+ - On restart, orphaned tasks are recovered from the database and resubmitted
12
+
13
+ ## Installation
14
+
15
+ ```bash
16
+ pip install django-tasks-local-db
17
+ ```
18
+
19
+ ## Configuration
20
+
21
+ ```python
22
+ INSTALLED_APPS = [
23
+ # ...
24
+ "django_tasks_local_db",
25
+ ]
26
+
27
+ TASKS = {
28
+ "default": {
29
+ "BACKEND": "django_tasks_local_db.LocalDBBackend",
30
+ "OPTIONS": {
31
+ "MAX_WORKERS": 4,
32
+ },
33
+ }
34
+ }
35
+ ```
36
+
37
+ Then run migrations:
38
+
39
+ ```bash
40
+ python manage.py migrate django_tasks_local_db
41
+ ```
@@ -0,0 +1,3 @@
1
+ from .backend import LocalDBBackend
2
+
3
+ __all__ = ["LocalDBBackend"]
@@ -0,0 +1,55 @@
1
+ from django.contrib import admin
2
+ from django.utils.html import format_html
3
+
4
+ from .models import DBTaskResult
5
+
6
+
7
+ @admin.register(DBTaskResult)
8
+ class DBTaskResultAdmin(admin.ModelAdmin):
9
+ list_display = [
10
+ "id",
11
+ "task_name",
12
+ "status",
13
+ "enqueued_at",
14
+ "started_at",
15
+ "finished_at",
16
+ "priority",
17
+ "queue_name",
18
+ ]
19
+ list_filter = ["status", "priority", "queue_name"]
20
+ readonly_fields = [
21
+ "id",
22
+ "task_name",
23
+ "task_path",
24
+ "status",
25
+ "enqueued_at",
26
+ "started_at",
27
+ "finished_at",
28
+ "priority",
29
+ "queue_name",
30
+ "backend_name",
31
+ "args_kwargs",
32
+ "return_value",
33
+ "exception_class_path",
34
+ "formatted_traceback",
35
+ ]
36
+ exclude = ["traceback", "worker_ids"]
37
+
38
+ def has_add_permission(self, request):
39
+ return False
40
+
41
+ def has_delete_permission(self, request, obj=None):
42
+ return False
43
+
44
+ def has_change_permission(self, request, obj=None):
45
+ return False
46
+
47
+ @admin.display(description="Task name")
48
+ def task_name(self, obj):
49
+ return obj.task_name
50
+
51
+ @admin.display(description="Traceback")
52
+ def formatted_traceback(self, obj):
53
+ if obj.traceback:
54
+ return format_html("<pre>{}</pre>", obj.traceback)
55
+ return ""
@@ -0,0 +1,52 @@
1
+ import logging
2
+
3
+ from django.apps import AppConfig
4
+
5
+ logger = logging.getLogger("django_tasks_local_db")
6
+
7
+
8
+ class DjangoTasksLocalDbConfig(AppConfig):
9
+ name = "django_tasks_local_db"
10
+ verbose_name = "Django Tasks Local DB"
11
+ default_auto_field = "django.db.models.BigAutoField"
12
+
13
+ def ready(self):
14
+ import threading
15
+
16
+ # Defer recovery until after Django is fully initialized.
17
+ # This avoids "database accessed during app initialization" warnings
18
+ # and ensures the task backends are fully configured.
19
+ thread = threading.Thread(target=self._recover_orphaned_tasks, daemon=True)
20
+ thread.start()
21
+
22
+ def _recover_orphaned_tasks(self):
23
+ import time
24
+
25
+ from django.conf import settings
26
+
27
+ # Brief delay to ensure Django startup completes
28
+ time.sleep(0.5)
29
+
30
+ from .backend import LocalDBBackend
31
+
32
+ tasks_settings = getattr(settings, "TASKS", {})
33
+ for alias, params in tasks_settings.items():
34
+ backend_path = params.get("BACKEND", "")
35
+ if "django_tasks_local_db" not in backend_path:
36
+ continue
37
+ try:
38
+ from django.tasks import task_backends
39
+
40
+ backend = task_backends[alias]
41
+ if isinstance(backend, LocalDBBackend):
42
+ recovered = backend.recover_tasks()
43
+ if recovered:
44
+ logger.info(
45
+ "Recovered %d orphaned task(s) for backend '%s'",
46
+ recovered,
47
+ alias,
48
+ )
49
+ except Exception:
50
+ logger.exception(
51
+ "Failed to recover tasks for backend '%s'", alias
52
+ )
@@ -0,0 +1,199 @@
1
+ import logging
2
+ from concurrent.futures import Future, ThreadPoolExecutor
3
+ from typing import Any
4
+
5
+ from django.db import close_old_connections, transaction
6
+ from django.tasks.backends.base import BaseTaskBackend
7
+ from django.tasks.base import Task, TaskContext, TaskResultStatus
8
+ from django.tasks.exceptions import TaskResultDoesNotExist
9
+ from django.tasks.signals import task_enqueued, task_finished, task_started
10
+ from django.utils.crypto import get_random_string
11
+ from django.utils.json import normalize_json
12
+ from django.utils.module_loading import import_string
13
+
14
+ from .state import get_executor_state, shutdown_executor
15
+
16
+ logger = logging.getLogger("django_tasks_local_db")
17
+
18
+
19
+ def _execute_task(
20
+ func_path: str,
21
+ args: tuple,
22
+ kwargs: dict,
23
+ result_id: str,
24
+ backend_name: str,
25
+ worker_id: str,
26
+ ):
27
+ """Execute a task function. Runs in the thread pool."""
28
+ from .models import DBTaskResult
29
+
30
+ close_old_connections()
31
+
32
+ db_result = DBTaskResult.objects.get(id=result_id)
33
+ db_result.claim(worker_id)
34
+
35
+ task = import_string(func_path)
36
+ task_result = db_result.task_result
37
+ backend_type = type(task.get_backend())
38
+
39
+ task_started.send(sender=backend_type, task_result=task_result)
40
+
41
+ if task.takes_context:
42
+ raw_return_value = task.call(
43
+ TaskContext(task_result=task_result), *args, **kwargs
44
+ )
45
+ else:
46
+ raw_return_value = task.call(*args, **kwargs)
47
+
48
+ return normalize_json(raw_return_value)
49
+
50
+
51
+ class LocalDBBackend(BaseTaskBackend):
52
+ supports_defer = False
53
+ supports_async_task = False
54
+ supports_get_result = True
55
+ supports_priority = False
56
+ executor_class = ThreadPoolExecutor
57
+
58
+ def __init__(self, alias: str, params: dict[str, Any]) -> None:
59
+ super().__init__(alias, params)
60
+ options = params.get("OPTIONS", {})
61
+ self._max_workers = options.get("MAX_WORKERS", 10)
62
+ self._name = f"tasks-{alias}"
63
+ self._worker_id = get_random_string(32)
64
+ self._state = None
65
+
66
+ def _get_state(self):
67
+ if self._state is None:
68
+ self._state = get_executor_state(
69
+ name=self._name,
70
+ executor_class=self.executor_class,
71
+ max_workers=self._max_workers,
72
+ )
73
+ return self._state
74
+
75
+ def enqueue(self, task: Task, args=None, kwargs=None):
76
+ from .models import DBTaskResult
77
+
78
+ self.validate_task(task)
79
+
80
+ func_path = task.module_path
81
+ normalized_args = normalize_json({"args": list(args or ()), "kwargs": dict(kwargs or {})})
82
+
83
+ db_result = DBTaskResult.objects.create(
84
+ args_kwargs=normalized_args,
85
+ priority=task.priority,
86
+ task_path=func_path,
87
+ queue_name=task.queue_name,
88
+ backend_name=self.alias,
89
+ exception_class_path="",
90
+ traceback="",
91
+ )
92
+
93
+ result_id = str(db_result.id)
94
+
95
+ task_enqueued.send(type(self), task_result=db_result.task_result)
96
+
97
+ state = self._get_state()
98
+ future = state.executor.submit(
99
+ _execute_task,
100
+ func_path,
101
+ tuple(normalized_args["args"]),
102
+ normalized_args["kwargs"],
103
+ result_id,
104
+ self.alias,
105
+ self._worker_id,
106
+ )
107
+
108
+ with state.lock:
109
+ state.futures[result_id] = future
110
+
111
+ future.add_done_callback(lambda f: self._on_complete(result_id, f))
112
+
113
+ return db_result.task_result
114
+
115
+ def _on_complete(self, result_id: str, future: Future) -> None:
116
+ from .models import DBTaskResult
117
+
118
+ try:
119
+ close_old_connections()
120
+
121
+ task_exc = None
122
+ return_value = None
123
+ try:
124
+ return_value = future.result()
125
+ except Exception as exc:
126
+ task_exc = exc
127
+
128
+ db_result = DBTaskResult.objects.get(id=result_id)
129
+ if task_exc is not None:
130
+ db_result.set_failed(task_exc)
131
+ else:
132
+ db_result.set_successful(return_value)
133
+
134
+ task_finished.send(
135
+ sender=type(self), task_result=db_result.task_result
136
+ )
137
+ finally:
138
+ state = self._get_state()
139
+ with state.lock:
140
+ state.futures.pop(result_id, None)
141
+
142
+ def get_result(self, result_id: str):
143
+ from .models import DBTaskResult
144
+
145
+ try:
146
+ return DBTaskResult.objects.get(id=result_id).task_result
147
+ except DBTaskResult.DoesNotExist as e:
148
+ raise TaskResultDoesNotExist(result_id) from e
149
+
150
+ def recover_tasks(self) -> int:
151
+ """Recover orphaned tasks from DB and resubmit to the executor.
152
+
153
+ Returns the number of tasks recovered.
154
+ """
155
+ from .models import DBTaskResult
156
+
157
+ recovered = 0
158
+ tasks_to_submit = []
159
+ with transaction.atomic():
160
+ orphaned = (
161
+ DBTaskResult.objects.filter(
162
+ status__in=[TaskResultStatus.READY, TaskResultStatus.RUNNING]
163
+ )
164
+ .filter(backend_name=self.alias)
165
+ .select_for_update(skip_locked=True)
166
+ )
167
+ for db_result in orphaned:
168
+ result_id = str(db_result.id)
169
+ db_result.claim(self._worker_id)
170
+ tasks_to_submit.append((
171
+ result_id,
172
+ db_result.task_path,
173
+ tuple(db_result.args_kwargs["args"]),
174
+ db_result.args_kwargs["kwargs"],
175
+ ))
176
+ recovered += 1
177
+ logger.info("Recovered orphaned task %s (%s)", result_id, db_result.task_path)
178
+
179
+ for result_id, task_path, args, kwargs in tasks_to_submit:
180
+ state = self._get_state()
181
+ future = state.executor.submit(
182
+ _execute_task,
183
+ task_path,
184
+ args,
185
+ kwargs,
186
+ result_id,
187
+ self.alias,
188
+ self._worker_id,
189
+ )
190
+ with state.lock:
191
+ state.futures[result_id] = future
192
+ future.add_done_callback(
193
+ lambda f, rid=result_id: self._on_complete(rid, f)
194
+ )
195
+
196
+ return recovered
197
+
198
+ def close(self):
199
+ shutdown_executor(self._name)
@@ -0,0 +1,104 @@
1
+ import datetime
2
+ import uuid
3
+
4
+ import django.db.models.functions.comparison
5
+ from django.db import migrations, models
6
+
7
+
8
+ class Migration(migrations.Migration):
9
+
10
+ initial = True
11
+
12
+ dependencies = []
13
+
14
+ operations = [
15
+ migrations.CreateModel(
16
+ name="DBTaskResult",
17
+ fields=[
18
+ (
19
+ "id",
20
+ models.UUIDField(
21
+ default=uuid.uuid4,
22
+ editable=False,
23
+ primary_key=True,
24
+ serialize=False,
25
+ ),
26
+ ),
27
+ (
28
+ "status",
29
+ models.CharField(
30
+ choices=[
31
+ ("READY", "Ready"),
32
+ ("RUNNING", "Running"),
33
+ ("FAILED", "Failed"),
34
+ ("SUCCESSFUL", "Successful"),
35
+ ],
36
+ default="READY",
37
+ max_length=10,
38
+ ),
39
+ ),
40
+ ("enqueued_at", models.DateTimeField(auto_now_add=True)),
41
+ ("started_at", models.DateTimeField(null=True)),
42
+ ("finished_at", models.DateTimeField(null=True)),
43
+ ("args_kwargs", models.JSONField()),
44
+ ("priority", models.IntegerField(default=0)),
45
+ ("task_path", models.TextField()),
46
+ ("worker_ids", models.JSONField(default=list)),
47
+ (
48
+ "queue_name",
49
+ models.CharField(default="default", max_length=32),
50
+ ),
51
+ ("backend_name", models.CharField(max_length=32)),
52
+ (
53
+ "run_after",
54
+ models.DateTimeField(
55
+ default=datetime.datetime(
56
+ 9999, 1, 1, 0, 0, tzinfo=datetime.timezone.utc
57
+ )
58
+ ),
59
+ ),
60
+ ("return_value", models.JSONField(default=None, null=True)),
61
+ ("exception_class_path", models.TextField(default="")),
62
+ ("traceback", models.TextField(default="")),
63
+ ],
64
+ options={
65
+ "ordering": [
66
+ django.db.models.expressions.OrderBy(
67
+ django.db.models.expressions.F("priority"), descending=True
68
+ ),
69
+ django.db.models.expressions.OrderBy(
70
+ django.db.models.expressions.F("run_after")
71
+ ),
72
+ ],
73
+ },
74
+ ),
75
+ migrations.AddIndex(
76
+ model_name="dbtaskresult",
77
+ index=models.Index(
78
+ "status",
79
+ django.db.models.expressions.OrderBy(
80
+ django.db.models.expressions.F("priority"), descending=True
81
+ ),
82
+ django.db.models.expressions.OrderBy(
83
+ django.db.models.expressions.F("run_after")
84
+ ),
85
+ condition=models.Q(("status", "READY")),
86
+ name="local_db_ready_idx",
87
+ ),
88
+ ),
89
+ migrations.AddIndex(
90
+ model_name="dbtaskresult",
91
+ index=models.Index(
92
+ fields=["backend_name"], name="django_task_backend_b87c8f_idx"
93
+ ),
94
+ ),
95
+ migrations.AddConstraint(
96
+ model_name="dbtaskresult",
97
+ constraint=models.CheckConstraint(
98
+ condition=models.Q(
99
+ ("priority__gte", -100), ("priority__lte", 100)
100
+ ),
101
+ name="local_db_priority_range",
102
+ ),
103
+ ),
104
+ ]
@@ -0,0 +1,102 @@
1
+ # Generated by Django 6.0.2 on 2026-03-03 17:28
2
+
3
+ import uuid
4
+ from django.db import migrations, models
5
+
6
+
7
+ class Migration(migrations.Migration):
8
+
9
+ dependencies = [
10
+ ('django_tasks_local_db', '0001_initial'),
11
+ ]
12
+
13
+ operations = [
14
+ migrations.AlterModelOptions(
15
+ name='dbtaskresult',
16
+ options={'ordering': [models.OrderBy(models.F('priority'), descending=True), models.OrderBy(models.F('run_after'))], 'verbose_name': 'task result', 'verbose_name_plural': 'task results'},
17
+ ),
18
+ migrations.RenameIndex(
19
+ model_name='dbtaskresult',
20
+ new_name='django_task_backend_0535b8_idx',
21
+ old_name='django_task_backend_b87c8f_idx',
22
+ ),
23
+ migrations.AlterField(
24
+ model_name='dbtaskresult',
25
+ name='args_kwargs',
26
+ field=models.JSONField(verbose_name='args kwargs'),
27
+ ),
28
+ migrations.AlterField(
29
+ model_name='dbtaskresult',
30
+ name='backend_name',
31
+ field=models.CharField(max_length=32, verbose_name='backend name'),
32
+ ),
33
+ migrations.AlterField(
34
+ model_name='dbtaskresult',
35
+ name='enqueued_at',
36
+ field=models.DateTimeField(auto_now_add=True, verbose_name='enqueued at'),
37
+ ),
38
+ migrations.AlterField(
39
+ model_name='dbtaskresult',
40
+ name='exception_class_path',
41
+ field=models.TextField(default='', verbose_name='exception class path'),
42
+ ),
43
+ migrations.AlterField(
44
+ model_name='dbtaskresult',
45
+ name='finished_at',
46
+ field=models.DateTimeField(null=True, verbose_name='finished at'),
47
+ ),
48
+ migrations.AlterField(
49
+ model_name='dbtaskresult',
50
+ name='id',
51
+ field=models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False, verbose_name='id'),
52
+ ),
53
+ migrations.AlterField(
54
+ model_name='dbtaskresult',
55
+ name='priority',
56
+ field=models.IntegerField(default=0, verbose_name='priority'),
57
+ ),
58
+ migrations.AlterField(
59
+ model_name='dbtaskresult',
60
+ name='queue_name',
61
+ field=models.CharField(default='default', max_length=32, verbose_name='queue name'),
62
+ ),
63
+ migrations.AlterField(
64
+ model_name='dbtaskresult',
65
+ name='return_value',
66
+ field=models.JSONField(default=None, null=True, verbose_name='return value'),
67
+ ),
68
+ migrations.AlterField(
69
+ model_name='dbtaskresult',
70
+ name='run_after',
71
+ field=models.DateTimeField(null=True, verbose_name='run after'),
72
+ ),
73
+ migrations.AlterField(
74
+ model_name='dbtaskresult',
75
+ name='started_at',
76
+ field=models.DateTimeField(null=True, verbose_name='started at'),
77
+ ),
78
+ migrations.AlterField(
79
+ model_name='dbtaskresult',
80
+ name='status',
81
+ field=models.CharField(choices=[('READY', 'Ready'), ('RUNNING', 'Running'), ('FAILED', 'Failed'), ('SUCCESSFUL', 'Successful')], default='READY', max_length=10, verbose_name='status'),
82
+ ),
83
+ migrations.AlterField(
84
+ model_name='dbtaskresult',
85
+ name='task_path',
86
+ field=models.TextField(verbose_name='task path'),
87
+ ),
88
+ migrations.AlterField(
89
+ model_name='dbtaskresult',
90
+ name='traceback',
91
+ field=models.TextField(default='', verbose_name='traceback'),
92
+ ),
93
+ migrations.AlterField(
94
+ model_name='dbtaskresult',
95
+ name='worker_ids',
96
+ field=models.JSONField(default=list, verbose_name='worker ids'),
97
+ ),
98
+ migrations.AddIndex(
99
+ model_name='dbtaskresult',
100
+ index=models.Index(fields=['queue_name'], name='django_task_queue_n_7c9efa_idx'),
101
+ ),
102
+ ]