# ADjango
> Sometimes I use this in different projects, so I decided to put it on pypi
`ADjango` — это удобная библиотека для упрощения работы с Django, которая предлагает различные полезные декораторы, утилиты для асинхронного программирования, планировщик задач для Celery, работу с транзакциями и многое другое.
## Installation
```bash
pip install adjango
```
## Settings
* ### Add the application to the project.
```python
INSTALLED_APPS = [
#...
'adjango',
]
```
* ### In `settings.py` set the params
```python
# adjango
from adjango.decorators import _handling_function
LOGIN_URL = '/login/'
ADJANGO_BACKENDS_APPS = BASE_DIR / 'apps'
ADJANGO_FRONTEND_APPS = BASE_DIR.parent / 'frontend' / 'src' / 'apps'
ADJANGO_APPS_PREPATH = 'apps.' # if apps in BASE_DIR/apps/app1,app2...
# ADJANGO_APPS_PREPATH = None # if in BASE_DIR/app1,app2...
# Override _handling_function so that unhandled exceptions are handled as you wish
ADJANGO_UNCAUGHT_EXCEPTION_HANDLING_FUNCTION = _handling_function
ADJANGO_CONTROLLERS_LOGGER_NAME = 'global'
ADJANGO_CONTROLLERS_LOGGING = True
ADJANGO_EMAIL_LOGGER_NAME = 'email'
```
```python
MIDDLEWARE = [
...
# add request.ip in views
'adjango.middleware.IPAddressMiddleware',
...
]
```
## Overview
Most functions, if available in asynchronous form, are also available in synchronous form.
* `aforce_data`
Декоратор `aforce_data` объединяет данные из `GET`, `POST` и `JSON` тела
запроса в `request.data`. Это упрощает доступ ко всем данным запроса в одном месте.
* `aatomic`
Асинхронный декоратор, который оборачивает
функцию в транзакционный контекст. Если происходит исключение, все изменения откатываются.
* `aatomic`
Асинхронный декоратор, который оборачивает
функцию в транзакционный контекст. Если происходит исключение, все изменения откатываются.
```python
from adjango.adecorators import acontroller
@acontroller(name='MyView', logger='custom_logger', log_name=True, log_time=True)
async def my_view(request):
pass
@acontroller('OneMoreView')
async def my_view_one_more(request):
pass
```
* `AsyncAtomicContextManager`
Асинхронный контекст-менеджер для работы с транзакциями, который обеспечивает атомарность операций.
```python
from adjango.utils.base import AsyncAtomicContextManager
async def some_function():
async with AsyncAtomicContextManager():
...
```
* `Tasker`
Класс Tasker предоставляет методы для планирования задач в `Celery` и `Celery Beat`.
```python
from adjango.utils.tasks import Tasker
task_id = Tasker.put(
task=my_celery_task,
param1='value1',
param2='value2',
countdown=60 # Задача выполнится через 60 секунд
)
```
```python
from adjango.utils.tasks import Tasker
from datetime import datetime
# Одноразовая задача через Celery Beat
Tasker.beat(
task=my_celery_task,
name='one_time_task',
schedule_time=datetime(2024, 10, 10, 14, 30), # Запуск задачи 10 октября 2024 года в 14:30
param1='value1',
param2='value2'
)
# Периодическая задача через Celery Beat (каждый час)
Tasker.beat(
task=my_celery_task,
name='hourly_task',
interval=3600, # Задача выполняется каждый час
param1='value1',
param2='value2'
)
```
* `send_emails`
Позволяет отправлять письма с использованием шаблонов и рендеринга контекста.
```python
from adjango.utils.mail import send_emails
send_emails(
subject='Welcome!',
emails=('user1@example.com', 'user2@example.com'),
template='emails/welcome.html',
context={'user': 'John Doe'}
)
```
```python
from adjango.tasks import send_emails_task
from adjango.utils.tasks import Tasker
send_emails_task.delay(
subject='Hello!',
emails=('user@example.com',),
template='emails/hello.html',
context={'message': 'Welcome to our service!'}
)
# or
Tasker.put(
task=send_emails_task,
subject='Hello!',
emails=('user@example.com',),
template='emails/hello.html',
context={'message': 'Welcome to our service!'},
countdown=60 # Задача выполнится через 5 секунд
)
```
Raw data
{
"_id": null,
"home_page": "https://github.com/Artasov/adjango",
"name": "adjango",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.8",
"maintainer_email": null,
"keywords": "adjango django utils funcs features async",
"author": "xlartas",
"author_email": "ivanhvalevskey@gmail.com",
"download_url": "https://files.pythonhosted.org/packages/53/fd/76ad1c36999e5a2feb8871b6d2a58a07343cd4b1ae83188f2e9e0f215d82/adjango-0.1.4.tar.gz",
"platform": null,
"description": "# ADjango \r\n\r\n> Sometimes I use this in different projects, so I decided to put it on pypi\r\n\r\n`ADjango` \u2014 \u044d\u0442\u043e \u0443\u0434\u043e\u0431\u043d\u0430\u044f \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u0434\u043b\u044f \u0443\u043f\u0440\u043e\u0449\u0435\u043d\u0438\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 Django, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u0435\u0442 \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0435 \u043f\u043e\u043b\u0435\u0437\u043d\u044b\u0435 \u0434\u0435\u043a\u043e\u0440\u0430\u0442\u043e\u0440\u044b, \u0443\u0442\u0438\u043b\u0438\u0442\u044b \u0434\u043b\u044f \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0433\u043e \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f, \u043f\u043b\u0430\u043d\u0438\u0440\u043e\u0432\u0449\u0438\u043a \u0437\u0430\u0434\u0430\u0447 \u0434\u043b\u044f Celery, \u0440\u0430\u0431\u043e\u0442\u0443 \u0441 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u044f\u043c\u0438 \u0438 \u043c\u043d\u043e\u0433\u043e\u0435 \u0434\u0440\u0443\u0433\u043e\u0435.\r\n\r\n## Installation\r\n```bash\r\npip install adjango\r\n```\r\n\r\n## Settings\r\n\r\n* ### Add the application to the project.\r\n ```python\r\n INSTALLED_APPS = [\r\n #...\r\n 'adjango',\r\n ]\r\n ```\r\n* ### In `settings.py` set the params\r\n ```python\r\n # adjango\r\n from adjango.decorators import _handling_function\r\n \r\n LOGIN_URL = '/login/'\r\n ADJANGO_BACKENDS_APPS = BASE_DIR / 'apps'\r\n ADJANGO_FRONTEND_APPS = BASE_DIR.parent / 'frontend' / 'src' / 'apps'\r\n ADJANGO_APPS_PREPATH = 'apps.' # if apps in BASE_DIR/apps/app1,app2...\r\n # ADJANGO_APPS_PREPATH = None # if in BASE_DIR/app1,app2...\r\n # Override _handling_function so that unhandled exceptions are handled as you wish\r\n ADJANGO_UNCAUGHT_EXCEPTION_HANDLING_FUNCTION = _handling_function\r\n ADJANGO_CONTROLLERS_LOGGER_NAME = 'global'\r\n ADJANGO_CONTROLLERS_LOGGING = True\r\n ADJANGO_EMAIL_LOGGER_NAME = 'email'\r\n ```\r\n ```python\r\n MIDDLEWARE = [\r\n ...\r\n # add request.ip in views\r\n 'adjango.middleware.IPAddressMiddleware', \r\n ...\r\n ]\r\n ```\r\n## Overview\r\nMost functions, if available in asynchronous form, are also available in synchronous form.\r\n* `aforce_data`\r\n\r\n \u0414\u0435\u043a\u043e\u0440\u0430\u0442\u043e\u0440 `aforce_data` \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u044f\u0435\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u0438\u0437 `GET`, `POST` \u0438 `JSON` \u0442\u0435\u043b\u0430 \r\n \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u0432 `request.data`. \u042d\u0442\u043e \u0443\u043f\u0440\u043e\u0449\u0430\u0435\u0442 \u0434\u043e\u0441\u0442\u0443\u043f \u043a\u043e \u0432\u0441\u0435\u043c \u0434\u0430\u043d\u043d\u044b\u043c \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u0432 \u043e\u0434\u043d\u043e\u043c \u043c\u0435\u0441\u0442\u0435.\r\n\r\n* `aatomic`\r\n\r\n \u0410\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0439 \u0434\u0435\u043a\u043e\u0440\u0430\u0442\u043e\u0440, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u0431\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u0435\u0442 \r\n \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0432 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u043e\u043d\u043d\u044b\u0439 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442. \u0415\u0441\u043b\u0438 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435, \u0432\u0441\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u043e\u0442\u043a\u0430\u0442\u044b\u0432\u0430\u044e\u0442\u0441\u044f.\r\n\r\n* `aatomic`\r\n\r\n \u0410\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0439 \u0434\u0435\u043a\u043e\u0440\u0430\u0442\u043e\u0440, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u0431\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u0435\u0442 \r\n \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0432 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u043e\u043d\u043d\u044b\u0439 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442. \u0415\u0441\u043b\u0438 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435, \u0432\u0441\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u043e\u0442\u043a\u0430\u0442\u044b\u0432\u0430\u044e\u0442\u0441\u044f.\r\n ```python\r\n from adjango.adecorators import acontroller\r\n\r\n @acontroller(name='MyView', logger='custom_logger', log_name=True, log_time=True)\r\n async def my_view(request):\r\n pass\r\n \r\n @acontroller('OneMoreView')\r\n async def my_view_one_more(request):\r\n pass\r\n ```\r\n* `AsyncAtomicContextManager`\r\n\r\n \u0410\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0439 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442-\u043c\u0435\u043d\u0435\u0434\u0436\u0435\u0440 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u044f\u043c\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u0435\u0442 \u0430\u0442\u043e\u043c\u0430\u0440\u043d\u043e\u0441\u0442\u044c \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0439.\r\n ```python\r\n from adjango.utils.base import AsyncAtomicContextManager\r\n \r\n async def some_function():\r\n async with AsyncAtomicContextManager():\r\n ... \r\n ```\r\n\r\n* `Tasker`\r\n\r\n \u041a\u043b\u0430\u0441\u0441 Tasker \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u043c\u0435\u0442\u043e\u0434\u044b \u0434\u043b\u044f \u043f\u043b\u0430\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0437\u0430\u0434\u0430\u0447 \u0432 `Celery` \u0438 `Celery Beat`.\r\n ```python\r\n from adjango.utils.tasks import Tasker\r\n \r\n task_id = Tasker.put(\r\n task=my_celery_task,\r\n param1='value1',\r\n param2='value2',\r\n countdown=60 # \u0417\u0430\u0434\u0430\u0447\u0430 \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 60 \u0441\u0435\u043a\u0443\u043d\u0434\r\n )\r\n ```\r\n ```python\r\n from adjango.utils.tasks import Tasker\r\n from datetime import datetime\r\n \r\n # \u041e\u0434\u043d\u043e\u0440\u0430\u0437\u043e\u0432\u0430\u044f \u0437\u0430\u0434\u0430\u0447\u0430 \u0447\u0435\u0440\u0435\u0437 Celery Beat\r\n Tasker.beat(\r\n task=my_celery_task,\r\n name='one_time_task',\r\n schedule_time=datetime(2024, 10, 10, 14, 30), # \u0417\u0430\u043f\u0443\u0441\u043a \u0437\u0430\u0434\u0430\u0447\u0438 10 \u043e\u043a\u0442\u044f\u0431\u0440\u044f 2024 \u0433\u043e\u0434\u0430 \u0432 14:30\r\n param1='value1',\r\n param2='value2'\r\n )\r\n \r\n # \u041f\u0435\u0440\u0438\u043e\u0434\u0438\u0447\u0435\u0441\u043a\u0430\u044f \u0437\u0430\u0434\u0430\u0447\u0430 \u0447\u0435\u0440\u0435\u0437 Celery Beat (\u043a\u0430\u0436\u0434\u044b\u0439 \u0447\u0430\u0441)\r\n Tasker.beat(\r\n task=my_celery_task,\r\n name='hourly_task',\r\n interval=3600, # \u0417\u0430\u0434\u0430\u0447\u0430 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u043a\u0430\u0436\u0434\u044b\u0439 \u0447\u0430\u0441\r\n param1='value1',\r\n param2='value2'\r\n )\r\n ```\r\n\r\n* `send_emails`\r\n\r\n \u041f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u043f\u0438\u0441\u044c\u043c\u0430 \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u0448\u0430\u0431\u043b\u043e\u043d\u043e\u0432 \u0438 \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u043d\u0433\u0430 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0430.\r\n ```python\r\n from adjango.utils.mail import send_emails\r\n \r\n send_emails(\r\n subject='Welcome!',\r\n emails=('user1@example.com', 'user2@example.com'),\r\n template='emails/welcome.html',\r\n context={'user': 'John Doe'}\r\n )\r\n ```\r\n ```python\r\n from adjango.tasks import send_emails_task\r\n from adjango.utils.tasks import Tasker\r\n \r\n send_emails_task.delay(\r\n subject='Hello!',\r\n emails=('user@example.com',),\r\n template='emails/hello.html',\r\n context={'message': 'Welcome to our service!'}\r\n )\r\n # or\r\n Tasker.put(\r\n task=send_emails_task,\r\n subject='Hello!',\r\n emails=('user@example.com',),\r\n template='emails/hello.html',\r\n context={'message': 'Welcome to our service!'},\r\n countdown=60 # \u0417\u0430\u0434\u0430\u0447\u0430 \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 5 \u0441\u0435\u043a\u0443\u043d\u0434\r\n )\r\n ```\r\n\r\n\r\n\r\n",
"bugtrack_url": null,
"license": null,
"summary": "A library with many features for interacting with Django",
"version": "0.1.4",
"project_urls": {
"Homepage": "https://github.com/Artasov/adjango",
"Source": "https://github.com/Artasov/adjango",
"Tracker": "https://github.com/Artasov/adjango/issues"
},
"split_keywords": [
"adjango",
"django",
"utils",
"funcs",
"features",
"async"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "49f6dcd3fcaca34d3f1451c62531d7ee32532ce47e531070665fabf41d747707",
"md5": "01811518ed50204a8ef496907e3b9944",
"sha256": "3df345124cd641cdd9bb7a03a65e4c933d3ee070d77fedcccd93c7cf1e844f44"
},
"downloads": -1,
"filename": "adjango-0.1.4-py3-none-any.whl",
"has_sig": false,
"md5_digest": "01811518ed50204a8ef496907e3b9944",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.8",
"size": 26268,
"upload_time": "2024-10-19T22:11:06",
"upload_time_iso_8601": "2024-10-19T22:11:06.256209Z",
"url": "https://files.pythonhosted.org/packages/49/f6/dcd3fcaca34d3f1451c62531d7ee32532ce47e531070665fabf41d747707/adjango-0.1.4-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "53fd76ad1c36999e5a2feb8871b6d2a58a07343cd4b1ae83188f2e9e0f215d82",
"md5": "a72dae18f2da973407da707b3849fe82",
"sha256": "859905081231a15e43464d1bb6edb2a53fd8209ac8d0f91161cf1dc2ed472b80"
},
"downloads": -1,
"filename": "adjango-0.1.4.tar.gz",
"has_sig": false,
"md5_digest": "a72dae18f2da973407da707b3849fe82",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.8",
"size": 20897,
"upload_time": "2024-10-19T22:11:07",
"upload_time_iso_8601": "2024-10-19T22:11:07.421050Z",
"url": "https://files.pythonhosted.org/packages/53/fd/76ad1c36999e5a2feb8871b6d2a58a07343cd4b1ae83188f2e9e0f215d82/adjango-0.1.4.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-10-19 22:11:07",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "Artasov",
"github_project": "adjango",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"requirements": [],
"lcname": "adjango"
}