Skip to content

Commit dff7de8

Browse files
committed
wrappers
1 parent 09128af commit dff7de8

File tree

12 files changed

+481
-0
lines changed

12 files changed

+481
-0
lines changed

LICENSE

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
MIT License
2+
3+
Copyright (c) 2021 Skander Ben Mahmoud
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

django_async_orm/__init__.py

Whitespace-only changes.

django_async_orm/apps.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import logging
2+
from django.apps import AppConfig, apps
3+
4+
from django_async_orm.manager import AsyncManager
5+
6+
7+
class AsyncOrmConfig(AppConfig):
8+
name = 'django_async_orm'
9+
10+
def ready(self):
11+
logging.info('AsyncORM: patching models')
12+
for model in apps.get_models(include_auto_created=True):
13+
model.objects = AsyncManager()
14+
model.objects.model = model

django_async_orm/manager.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
2+
3+
from django.db.models.manager import BaseManager
4+
5+
from django_async_orm.query import QuerySetAsync
6+
7+
8+
class AsyncManager(BaseManager.from_queryset(QuerySetAsync)):
9+
pass

django_async_orm/models.py

Whitespace-only changes.

django_async_orm/query.py

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
import concurrent
2+
3+
from asgiref.sync import sync_to_async
4+
5+
# Create your models here.
6+
from django.db.models import QuerySet
7+
8+
from django_async_orm.utils import AsyncIter
9+
10+
11+
class QuerySetAsync(QuerySet):
12+
13+
def __init__(self, model=None, query=None, using=None, hints=None):
14+
super().__init__(model, query, using, hints)
15+
16+
async def async_get(self, *args, **kwargs):
17+
return await sync_to_async(self.get, thread_sensitive=1)(*args, **kwargs)
18+
19+
async def async_create(self, **kwargs):
20+
return await sync_to_async(self.create, thread_sensitive=True)(**kwargs)
21+
22+
async def async_bulk_create(self, obs, batch_size=None, ignore_conflicts=False):
23+
return await sync_to_async(self.bulk_create, thread_sensitive=True)(obs, batch_size=batch_size,
24+
ignore_conflicts=ignore_conflicts)
25+
26+
async def async_bulk_update(self, objs, fields, batch_size=None):
27+
return await sync_to_async(self.bulk_update, thread_sensitive=True)(objs=objs, fields=fields,
28+
batch_size=batch_size)
29+
30+
async def async_get_or_create(self, defaults=None, **kwargs):
31+
return await sync_to_async(self.get_or_create, thread_sensitive=True)(defaults=defaults, **kwargs)
32+
33+
async def async_update_or_create(self, defaults=None, **kwargs):
34+
return await sync_to_async(self.update_or_create, thread_sensitive=True)(defaults=defaults, **kwargs)
35+
36+
async def async_earliest(self, *fields):
37+
return await sync_to_async(self.earliest, thread_sensitive=True)(*fields)
38+
39+
async def async_latest(self, *fields):
40+
return await sync_to_async(self.latest, thread_sensitive=True)(*fields)
41+
42+
async def async_first(self):
43+
return await sync_to_async(self.first, thread_sensitive=True)()
44+
45+
async def async_last(self):
46+
return await sync_to_async(self.last, thread_sensitive=True)()
47+
48+
async def async_in_bulk(self, id_list=None, *_, field_name='pk'):
49+
return await sync_to_async(self.in_bulk, thread_sensitive=True)(id_list=id_list, *_, field_name=field_name)
50+
51+
async def async_delete(self):
52+
return await sync_to_async(self.delete, thread_sensitive=True)()
53+
54+
async def async_update(self, **kwargs):
55+
return await sync_to_async(self.update, thread_sensitive=True)(**kwargs)
56+
57+
async def async_exists(self):
58+
return await sync_to_async(self.exists, thread_sensitive=True)()
59+
60+
async def async_explain(self, *_, format=None, **options):
61+
return await sync_to_async(self.explain, thread_sensitive=True)(*_, format=format, **options)
62+
63+
async def async_raw(self, raw_query, params=None, translations=None, using=None):
64+
return await sync_to_async(self.raw, thread_sensitive=True)(raw_query, params=params, translations=translations,
65+
using=using)
66+
67+
def __aiter__(self):
68+
with concurrent.futures.ThreadPoolExecutor(max_workers=1) as executor:
69+
executor.submit(self._fetch_all)
70+
71+
return AsyncIter(self._result_cache)
72+
73+
def __repr__(self):
74+
with concurrent.futures.ThreadPoolExecutor(max_workers=1) as executor:
75+
future_repr = executor.submit(super(QuerySetAsync, self).__repr__)
76+
77+
return future_repr.result()
78+
79+
##################################################################
80+
# PUBLIC METHODS THAT ALTER ATTRIBUTES AND RETURN A NEW QUERYSET #
81+
##################################################################
82+
83+
async def async_all(self):
84+
return await sync_to_async(self.all, thread_sensitive=True)()
85+
86+
async def async_filter(self, *args, **kwargs):
87+
return await sync_to_async(self.filter, thread_sensitive=True)(*args, **kwargs)
88+
89+
async def async_exclude(self, *args, **kwargs):
90+
return await sync_to_async(self.exclude, thread_sensitive=True)(*args, **kwargs)
91+
92+
async def async_complex_filter(self, filter_obj):
93+
return await sync_to_async(self.complex_filter, thread_sensitive=True)(filter_obj)
94+
95+
async def async_union(self, *other_qs, all=False):
96+
return await sync_to_async(self.union, thread_sensitive=True)(*other_qs, all=all)
97+
98+
async def async_intersection(self, *other_qs):
99+
return await sync_to_async(self.intersection, thread_sensitive=True)(*other_qs)
100+
101+
async def async_difference(self, *other_qs):
102+
return await sync_to_async(self.difference, thread_sensitive=True)(*other_qs)
103+
104+
async def async_select_for_update(self, nowait=False, skip_locked=False, of=()):
105+
return await sync_to_async(self.select_for_update, thread_sensitive=True)(nowait=nowait,
106+
skip_locked=skip_locked, of=of)
107+
108+
async def async_prefetch_related(self, *lookups):
109+
return await sync_to_async(self.prefetch_related, thread_sensitive=True)(*lookups)
110+
111+
async def async_annotate(self, *args, **kwargs):
112+
return await sync_to_async(self.annotate, thread_sensitive=True)(*args, **kwargs)
113+
114+
async def async_order_by(self, *field_names):
115+
return await sync_to_async(self.order_by, thread_sensitive=True)(*field_names)
116+
117+
async def async_distinct(self, *field_names):
118+
return await sync_to_async(self.distinct, thread_sensitive=True)(*field_names)
119+
120+
async def async_extra(self, select=None, where=None, params=None, tables=None, order_by=None, select_params=None):
121+
return await sync_to_async(self.extra, thread_sensitive=True)(select, where, params, tables, order_by,
122+
select_params)
123+
124+
async def async_reverse(self):
125+
return await sync_to_async(self.reverse, thread_sensitive=True)()
126+
127+
async def async_defer(self, *fields):
128+
return await sync_to_async(self.defer, thread_sensitive=True)(*fields)
129+
130+
async def async_only(self, *fields):
131+
return await sync_to_async(self.only, thread_sensitive=True)(*fields)
132+
133+
async def async_using(self, alias):
134+
return await sync_to_async(self.using, thread_sensitive=True)(alias)
135+
136+
async def async_resolve_expression(self, *args, **kwargs):
137+
return await sync_to_async(self.resolve_expression, thread_sensitive=True)(*args, **kwargs)
138+
139+
@property
140+
async def async_ordered(self):
141+
def _ordered():
142+
return super(QuerySetAsync, self).ordered
143+
return await sync_to_async(_ordered, thread_sensitive=True)()

django_async_orm/utils.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import asyncio
2+
3+
class AsyncIter:
4+
def __init__(self, iterable):
5+
self._iter = iter(iterable)
6+
7+
def __aiter__(self):
8+
return self
9+
10+
async def __anext__(self):
11+
try:
12+
element = next(self._iter)
13+
except StopIteration:
14+
raise StopAsyncIteration
15+
await asyncio.sleep(0)
16+
return element

django_async_orm/wrappers.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
from asgiref.sync import sync_to_async
2+
from django.contrib.auth import login, logout
3+
4+
5+
def _sync_render(*args, **kwargs):
6+
from django.shortcuts import render
7+
return render(*args, **kwargs)
8+
9+
10+
async_render = sync_to_async(_sync_render, thread_sensitive=True)
11+
12+
13+
def _sync_login(*args, **kwargs):
14+
return login(*args, *kwargs)
15+
16+
17+
async_login = sync_to_async(_sync_login, thread_sensitive=True)
18+
19+
20+
def _sync_logout(request):
21+
return logout(request)
22+
23+
24+
async_logout = sync_to_async(_sync_logout, thread_sensitive=True)
25+
26+
27+
def _sync_form_is_valid(form_instance):
28+
return form_instance.is_valid()
29+
30+
31+
async_form_is_valid = sync_to_async(_sync_form_is_valid, thread_sensitive=True)

0 commit comments

Comments
 (0)