├── core
├── __init__.py
├── asgi.py
├── wsgi.py
├── urls.py
└── settings.py
├── robot
├── __init__.py
├── management
│ ├── __init__.py
│ └── commands
│ │ └── runbot.py
├── migrations
│ ├── __init__.py
│ ├── 0004_delete_permission.py
│ ├── 0002_alter_telegramuser_username.py
│ ├── 0003_alter_permission_name.py
│ └── 0001_initial.py
├── handlers
│ ├── groups
│ │ └── __init__.py
│ ├── errors
│ │ ├── __init__.py
│ │ └── error_handler.py
│ ├── __init__.py
│ └── users
│ │ ├── __init__.py
│ │ ├── echo.py
│ │ ├── help.py
│ │ ├── midjourney.py
│ │ ├── cancel.py
│ │ ├── start.py
│ │ ├── example.py
│ │ ├── contact.py
│ │ └── create.py
├── utils
│ ├── db_api
│ │ └── __init__.py
│ ├── misc
│ │ ├── __init__.py
│ │ ├── logging.py
│ │ └── throttling.py
│ ├── __init__.py
│ ├── set_bot_commands.py
│ └── notify_admins.py
├── keyboards
│ ├── inline
│ │ └── __init__.py
│ ├── __init__.py
│ └── default
│ │ ├── __init__.py
│ │ └── user_register.py
├── media
│ └── example
│ │ ├── hire.jpg
│ │ ├── example_1.jpg
│ │ ├── example_2.jpg
│ │ ├── example_3.jpg
│ │ └── nav-brend.jpg
├── states
│ ├── __init__.py
│ ├── create_image.py
│ ├── admin_message.py
│ └── user_register.py
├── apps.py
├── middlewares
│ ├── __init__.py
│ └── throttling.py
├── admin.py
└── models.py
├── requirements.txt
├── loader.py
├── .env.template
├── README.md
├── manage.py
├── const_texts.py
└── .gitignore
/core/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/robot/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/robot/management/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/robot/migrations/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/robot/handlers/groups/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/robot/utils/db_api/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/robot/keyboards/inline/__init__.py:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/robot/handlers/errors/__init__.py:
--------------------------------------------------------------------------------
1 | from . import error_handler
2 |
--------------------------------------------------------------------------------
/robot/keyboards/__init__.py:
--------------------------------------------------------------------------------
1 | from . import default
2 | from . import inline
3 |
--------------------------------------------------------------------------------
/robot/keyboards/default/__init__.py:
--------------------------------------------------------------------------------
1 | from .user_register import make_buttons
2 |
--------------------------------------------------------------------------------
/robot/utils/misc/__init__.py:
--------------------------------------------------------------------------------
1 | from .throttling import rate_limit
2 | from . import logging
3 |
--------------------------------------------------------------------------------
/robot/handlers/__init__.py:
--------------------------------------------------------------------------------
1 | from . import errors
2 | from . import users
3 | from . import groups
4 |
--------------------------------------------------------------------------------
/robot/utils/__init__.py:
--------------------------------------------------------------------------------
1 | from . import db_api
2 | from . import misc
3 | from .notify_admins import on_startup_notify
4 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | aiogram==2.23.1
2 | Django==4.1.4
3 | environs==9.5.0
4 | replicate==0.4.0
5 | Pillow==9.4.0
6 | psycopg2==2.9.5
--------------------------------------------------------------------------------
/robot/media/example/hire.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bekmuxtorov/midjourney-telegram-bot/HEAD/robot/media/example/hire.jpg
--------------------------------------------------------------------------------
/robot/media/example/example_1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bekmuxtorov/midjourney-telegram-bot/HEAD/robot/media/example/example_1.jpg
--------------------------------------------------------------------------------
/robot/media/example/example_2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bekmuxtorov/midjourney-telegram-bot/HEAD/robot/media/example/example_2.jpg
--------------------------------------------------------------------------------
/robot/media/example/example_3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bekmuxtorov/midjourney-telegram-bot/HEAD/robot/media/example/example_3.jpg
--------------------------------------------------------------------------------
/robot/media/example/nav-brend.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bekmuxtorov/midjourney-telegram-bot/HEAD/robot/media/example/nav-brend.jpg
--------------------------------------------------------------------------------
/robot/states/__init__.py:
--------------------------------------------------------------------------------
1 | from .user_register import UserRegister
2 | from .create_image import CreateImage
3 | from .admin_message import Contact
4 |
--------------------------------------------------------------------------------
/robot/states/create_image.py:
--------------------------------------------------------------------------------
1 | from aiogram.dispatcher.filters.state import StatesGroup, State
2 |
3 |
4 | class CreateImage(StatesGroup):
5 | create_image = State()
6 |
--------------------------------------------------------------------------------
/robot/states/admin_message.py:
--------------------------------------------------------------------------------
1 | from aiogram.dispatcher.filters.state import StatesGroup, State
2 |
3 |
4 | class Contact(StatesGroup):
5 | admin_message = State()
6 | send_admin = State()
7 |
--------------------------------------------------------------------------------
/robot/utils/misc/logging.py:
--------------------------------------------------------------------------------
1 | import logging
2 |
3 | logging.basicConfig(
4 | format=u'%(filename)s [LINE:%(lineno)d] #%(levelname)-8s [%(asctime)s] %(message)s',
5 | level=logging.INFO,
6 | )
7 |
--------------------------------------------------------------------------------
/robot/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 |
3 |
4 | class RobotConfig(AppConfig):
5 | default_auto_field = 'django.db.models.BigAutoField'
6 | name = 'robot'
7 | verbose_name = 'Telegram bot'
8 |
--------------------------------------------------------------------------------
/robot/handlers/users/__init__.py:
--------------------------------------------------------------------------------
1 | from . import help
2 | from . import start
3 | from . import create
4 | from . import example
5 | from . import midjourney
6 | from . import contact
7 | from . import cancel
8 | from . import echo
9 |
--------------------------------------------------------------------------------
/robot/middlewares/__init__.py:
--------------------------------------------------------------------------------
1 | from aiogram import Dispatcher
2 |
3 | from loader import dp
4 | from .throttling import ThrottlingMiddleware
5 |
6 |
7 | if __name__ == "middlewares":
8 | dp.middleware.setup(ThrottlingMiddleware())
9 |
--------------------------------------------------------------------------------
/robot/handlers/users/echo.py:
--------------------------------------------------------------------------------
1 | from aiogram import types
2 |
3 | from loader import dp
4 |
5 |
6 | # Echo bot
7 | @dp.message_handler(state=None)
8 | async def bot_echo(message: types.Message):
9 | await message.answer(message.text)
10 |
--------------------------------------------------------------------------------
/robot/states/user_register.py:
--------------------------------------------------------------------------------
1 | from aiogram.dispatcher.filters.state import StatesGroup, State
2 |
3 |
4 | class UserRegister(StatesGroup):
5 | username = State()
6 | first_name = State()
7 | last_name = State()
8 | password = State()
9 |
--------------------------------------------------------------------------------
/loader.py:
--------------------------------------------------------------------------------
1 | from aiogram import Bot, Dispatcher, types
2 | from aiogram.contrib.fsm_storage.memory import MemoryStorage
3 | from django.conf import settings
4 |
5 |
6 | bot = Bot(token=settings.BOT_TOKEN, parse_mode=types.ParseMode.HTML)
7 | storage = MemoryStorage()
8 | dp = Dispatcher(bot, storage=storage)
9 |
--------------------------------------------------------------------------------
/robot/utils/set_bot_commands.py:
--------------------------------------------------------------------------------
1 | from aiogram import types
2 |
3 |
4 | async def set_default_commands(dp):
5 | await dp.bot.set_my_commands(
6 | [
7 | types.BotCommand("start", "Botni ishga tushurish"),
8 | types.BotCommand("help", "Yordam"),
9 | ]
10 | )
11 |
--------------------------------------------------------------------------------
/.env.template:
--------------------------------------------------------------------------------
1 | SECRET_KEY=django-insecure
2 | DEBUG=True
3 | ALLOWED_HOSTS=localhost,127.0.0.1
4 |
5 | BOT_TOKEN=527407998:AAEhQD8PPUw
6 | ADMINS_LIST=51256566641
7 |
8 | REPLICATE_API_TOKEN=
9 |
10 | DB_TYPE=postgres
11 | DB_NAME=your_db_name
12 | DB_USER=your_db_user
13 | DB_PASSWORD=your_password
14 | DB_HOST=localhost
15 | DB_PORT=5432
--------------------------------------------------------------------------------
/robot/utils/notify_admins.py:
--------------------------------------------------------------------------------
1 | import logging
2 |
3 | from aiogram import Dispatcher
4 |
5 | from django.conf import settings
6 |
7 |
8 | async def on_startup_notify(dp: Dispatcher):
9 | for admin in settings.ADMINS_LIST:
10 | try:
11 | await dp.bot.send_message(admin, "Bot ishga tushirildi")
12 |
13 | except Exception as err:
14 | logging.exception(err)
15 |
--------------------------------------------------------------------------------
/robot/migrations/0004_delete_permission.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 4.1.4 on 2023-03-26 17:13
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ('robot', '0003_alter_permission_name'),
10 | ]
11 |
12 | operations = [
13 | migrations.DeleteModel(
14 | name='Permission',
15 | ),
16 | ]
17 |
--------------------------------------------------------------------------------
/robot/handlers/users/help.py:
--------------------------------------------------------------------------------
1 | from aiogram import types
2 | from aiogram.dispatcher.filters.builtin import CommandHelp
3 |
4 | from loader import dp
5 |
6 |
7 | @dp.message_handler(CommandHelp())
8 | async def bot_help(message: types.Message):
9 | text = ("Buyruqlar: ",
10 | "/start - Botni ishga tushirish",
11 | "/help - Yordam")
12 |
13 | await message.answer("\n".join(text))
14 |
--------------------------------------------------------------------------------
/robot/utils/misc/throttling.py:
--------------------------------------------------------------------------------
1 | def rate_limit(limit: int, key=None):
2 | """
3 | Decorator for configuring rate limit and key in different functions.
4 |
5 | :param limit:
6 | :param key:
7 | :return:
8 | """
9 |
10 | def decorator(func):
11 | setattr(func, 'throttling_rate_limit', limit)
12 | if key:
13 | setattr(func, 'throttling_key', key)
14 | return func
15 |
16 | return decorator
17 |
--------------------------------------------------------------------------------
/core/asgi.py:
--------------------------------------------------------------------------------
1 | """
2 | ASGI config for core project.
3 |
4 | It exposes the ASGI callable as a module-level variable named ``application``.
5 |
6 | For more information on this file, see
7 | https://docs.djangoproject.com/en/4.1/howto/deployment/asgi/
8 | """
9 |
10 | import os
11 |
12 | from django.core.asgi import get_asgi_application
13 |
14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'core.settings')
15 |
16 | application = get_asgi_application()
17 |
--------------------------------------------------------------------------------
/core/wsgi.py:
--------------------------------------------------------------------------------
1 | """
2 | WSGI config for core project.
3 |
4 | It exposes the WSGI callable as a module-level variable named ``application``.
5 |
6 | For more information on this file, see
7 | https://docs.djangoproject.com/en/4.1/howto/deployment/wsgi/
8 | """
9 |
10 | import os
11 |
12 | from django.core.wsgi import get_wsgi_application
13 |
14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'core.settings')
15 |
16 | application = get_wsgi_application()
17 |
--------------------------------------------------------------------------------
/robot/keyboards/default/user_register.py:
--------------------------------------------------------------------------------
1 | from aiogram.types import ReplyKeyboardMarkup, KeyboardButton
2 | from const_texts import c_cancel
3 |
4 |
5 | def make_buttons(words: list, row_width: int = 1) -> ReplyKeyboardMarkup:
6 | buttons_group = ReplyKeyboardMarkup(
7 | row_width=row_width, resize_keyboard=True)
8 | for word in words:
9 | if word is not None:
10 | buttons_group.insert(KeyboardButton(text=word))
11 | return buttons_group
12 |
--------------------------------------------------------------------------------
/robot/handlers/users/midjourney.py:
--------------------------------------------------------------------------------
1 | import replicate
2 | from environs import Env
3 |
4 | env = Env()
5 | env.read_env()
6 |
7 | # Set the REPLICATE_API_TOKEN environment variable
8 | REPLICATE_API_TOKEN = env.str("REPLICATE_API_TOKEN")
9 | model = replicate.models.get("tstramer/midjourney-diffusion")
10 | version = model.versions.get(
11 | "436b051ebd8f68d23e83d22de5e198e0995357afef113768c20f0b6fcef23c8b")
12 |
13 |
14 | def draw_picture(input: str, version: str = version) -> str:
15 | return version.predict(prompt=input)
16 |
--------------------------------------------------------------------------------
/robot/migrations/0002_alter_telegramuser_username.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 4.1.4 on 2023-01-13 12:56
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ('robot', '0001_initial'),
10 | ]
11 |
12 | operations = [
13 | migrations.AlterField(
14 | model_name='telegramuser',
15 | name='username',
16 | field=models.CharField(blank=True, default='Nomalum', max_length=40, null=True, verbose_name='Username'),
17 | ),
18 | ]
19 |
--------------------------------------------------------------------------------
/robot/migrations/0003_alter_permission_name.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 4.1.4 on 2023-03-26 00:42
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ('robot', '0002_alter_telegramuser_username'),
10 | ]
11 |
12 | operations = [
13 | migrations.AlterField(
14 | model_name='permission',
15 | name='name',
16 | field=models.CharField(choices=[('midjourney', 'Midjourney'), ('googletrans', 'Googletrans')], max_length=100, verbose_name='API nomi'),
17 | ),
18 | ]
19 |
--------------------------------------------------------------------------------
/robot/handlers/users/cancel.py:
--------------------------------------------------------------------------------
1 | from aiogram import types
2 | from aiogram.dispatcher import FSMContext
3 |
4 | from robot.keyboards.default import make_buttons
5 | from const_texts import c_create, c_example, c_contact, c_cancel
6 | from loader import dp
7 |
8 |
9 | # Echo bot
10 | @dp.message_handler(text=c_cancel, state='*')
11 | async def bot_start(message: types.Message, state: FSMContext):
12 | await state.finish()
13 | await message.answer(
14 | text="Yaxshi. Ortga qaytamiz.",
15 | reply_markup=make_buttons(
16 | words=[c_create, c_example, c_contact],
17 | row_width=2
18 | )
19 | )
20 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Django + Aiogram
2 |
3 | ## 1. Create virtualenv and activate
4 |
5 | ```sh
6 | python3 -m virtualenv venv
7 | source venv/bin/activate
8 | ```
9 |
10 | ## 2. Install required packages
11 |
12 | ```sh
13 | pip install -r requirements.txt
14 | ```
15 |
16 | ## 3. Create ```.env``` file using env template file and fill it
17 |
18 | ```sh
19 | cp .env.template .env
20 | ```
21 |
22 | ## 4. Run django project
23 |
24 | - Migrations
25 |
26 | ```sh
27 | python manage.py migrate
28 | ```
29 |
30 | - Run server
31 |
32 | ```sh
33 | python manage.py runserver
34 | ```
35 |
36 | ## 5. Run aiogram project
37 |
38 | ```sh
39 | python manage.py runbot
40 | ```
41 |
--------------------------------------------------------------------------------
/robot/management/commands/runbot.py:
--------------------------------------------------------------------------------
1 | from django.core.management.base import BaseCommand, CommandError
2 |
3 | from aiogram import executor
4 |
5 | from loader import dp
6 |
7 | from robot.middlewares import *
8 | from robot.handlers import *
9 |
10 | from robot.utils.notify_admins import on_startup_notify
11 | from robot.utils.set_bot_commands import set_default_commands
12 |
13 |
14 | async def on_startup(dispatcher):
15 | await set_default_commands(dispatcher)
16 | await on_startup_notify(dispatcher)
17 |
18 |
19 | class Command(BaseCommand):
20 | help = 'RUN COMMAND: python manage.py runbot'
21 |
22 | def handle(self, *args, **options):
23 | executor.start_polling(dp, on_startup=on_startup)
24 |
--------------------------------------------------------------------------------
/manage.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | """Django's command-line utility for administrative tasks."""
3 | import os
4 | import sys
5 |
6 |
7 | def main():
8 | """Run administrative tasks."""
9 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'core.settings')
10 | try:
11 | from django.core.management import execute_from_command_line
12 | except ImportError as exc:
13 | raise ImportError(
14 | "Couldn't import Django. Are you sure it's installed and "
15 | "available on your PYTHONPATH environment variable? Did you "
16 | "forget to activate a virtual environment?"
17 | ) from exc
18 | execute_from_command_line(sys.argv)
19 |
20 |
21 | if __name__ == '__main__':
22 | main()
23 |
--------------------------------------------------------------------------------
/robot/admin.py:
--------------------------------------------------------------------------------
1 | from django.contrib import admin
2 | from .models import TelegramUser, Example, Request, Message
3 |
4 |
5 | class TelegramUserAdmin(admin.ModelAdmin):
6 | list_display = ['id', 'full_name', 'get_username',
7 | 'tg_id', 'request_all_count']
8 | search_fields = ['full_name']
9 |
10 |
11 | class ExampleAdmin(admin.ModelAdmin):
12 | list_display = ['id', 'description', 'create_date']
13 | ordering = ['-create_date']
14 |
15 |
16 | class RequestAdmin(admin.ModelAdmin):
17 | list_display = ['id', 'user', 'get_date']
18 | search_fields = ['user']
19 |
20 |
21 | class MessageAdmin(admin.ModelAdmin):
22 | list_display = ['id', 'user', 'get_username',
23 | 'get_date', 'get_message']
24 | search_fields = ['user']
25 |
26 |
27 | admin.site.register(TelegramUser, TelegramUserAdmin)
28 | admin.site.register(Example, ExampleAdmin)
29 | admin.site.register(Request, RequestAdmin)
30 | admin.site.register(Message, MessageAdmin)
31 |
--------------------------------------------------------------------------------
/core/urls.py:
--------------------------------------------------------------------------------
1 | """core URL Configuration
2 |
3 | The `urlpatterns` list routes URLs to views. For more information please see:
4 | https://docs.djangoproject.com/en/4.1/topics/http/urls/
5 | Examples:
6 | Function views
7 | 1. Add an import: from my_app import views
8 | 2. Add a URL to urlpatterns: path('', views.home, name='home')
9 | Class-based views
10 | 1. Add an import: from other_app.views import Home
11 | 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
12 | Including another URLconf
13 | 1. Import the include() function: from django.urls import include, path
14 | 2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
15 | """
16 | from django.contrib import admin
17 | from django.urls import path
18 | from django.conf import settings
19 | from django.conf.urls.static import static
20 |
21 | urlpatterns = [
22 | path('admin/', admin.site.urls),
23 | ]
24 |
25 | urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
26 | urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
27 |
--------------------------------------------------------------------------------
/robot/handlers/users/start.py:
--------------------------------------------------------------------------------
1 | import logging
2 |
3 | from asgiref.sync import sync_to_async
4 | from robot.models import TelegramUser
5 |
6 | from aiogram import types
7 | from aiogram.dispatcher.filters.builtin import CommandStart
8 |
9 | from loader import dp, bot
10 | from const_texts import c_get_hello, c_about_us, c_create, c_example, c_contact
11 | from robot.keyboards.default import make_buttons
12 |
13 |
14 | @dp.message_handler(CommandStart())
15 | async def bot_start(message: types.Message):
16 | telegram_user, _ = await TelegramUser.objects.aget_or_create(
17 | full_name=message.from_user.full_name,
18 | username=message.from_user.username,
19 | tg_id=message.from_user.id,
20 | chat_id=message.chat.id,
21 | )
22 | logging.info("New user")
23 | chat_id = message.from_user.id
24 | await bot.send_animation(
25 | chat_id=chat_id,
26 | animation="https://t.me/sinovuchun4101/15",
27 | caption=c_get_hello(message.from_user.full_name),
28 | reply_markup=make_buttons(
29 | words=[c_create, c_example, c_contact],
30 | row_width=2
31 | )
32 | )
33 |
--------------------------------------------------------------------------------
/robot/handlers/users/example.py:
--------------------------------------------------------------------------------
1 | from asgiref.sync import sync_to_async
2 | from aiogram import types
3 | from aiogram.types.input_file import InputFile
4 |
5 | from loader import dp, bot
6 | from const_texts import c_example, c_example_get_caption, c_create, c_contact, c_null_base
7 | from robot.models import Example
8 | from robot.keyboards.default import make_buttons
9 |
10 |
11 | def get_image(image_url):
12 | return InputFile(path_or_bytesio=image_url)
13 |
14 |
15 | @dp.message_handler(text=c_example)
16 | async def bot_echo(message: types.Message):
17 | try:
18 | chat_id = message.from_user.id
19 | example_photos = await sync_to_async(list)(Example.objects.all())
20 | for indx, example_photo in enumerate(example_photos, start=1):
21 | await bot.send_photo(
22 | chat_id=chat_id,
23 | photo=get_image(example_photo.image.path),
24 | caption=c_example_get_caption(example_photo.description, indx),
25 | reply_markup=make_buttons(
26 | words=[c_create, c_example, c_contact],
27 | row_width=2
28 | )
29 | )
30 |
31 | except Exception:
32 | print('='*5 + c_null_base + '='*5)
33 | await message.answer(text=c_null_base)
34 |
--------------------------------------------------------------------------------
/const_texts.py:
--------------------------------------------------------------------------------
1 | def c_get_hello(full_name: str) -> str:
2 | return f"Assalomu alaykum, {full_name.title()}\nBu Midjorneydan to'g'ridan-to'g'ri telegramda mavjud bo'lgan bot!\n\n" \
3 | "🔥Endi siz messenjerdan chiqmasdan matn tavsifiga muvofiq istalgan tasvirni yaratishingiz mumkin!\n\n"\
4 | "Namunalarni ko'rish uchun bosing👇"
5 |
6 |
7 | def c_example_get_caption(description: str, indx: int = 0) -> str:
8 | if indx != 0:
9 | return f'{indx} - namuna \n\n' \
10 | f"Tavsif: {description}"
11 | else:
12 | return f"\n\nTavsif: {description}\n\n👉@midjourney_imagebot"
13 |
14 |
15 | c_create_description = 'Marhamat tassavuringizdagi suratni so\'zlar yordamida bayon qilib bering. \n\n🖋Matnni kiriting...'
16 | c_null_base = 'Bizda hali namunalar mavjud emas.'
17 | c_example = 'Namunalar🏞'
18 | c_create = 'Yaratish🤖'
19 | c_contact = '📑Bog\'lanish'
20 | c_about_us = "Biz haqimizda 👁️"
21 | c_error_words = '🛠Botda texnik ishlar olib borilmoqda. Birozdan keyin qayta urinib ko\'ring.\n\nKeltirilgan noqulayliklar uchun uzr so\'raymiz!'
22 | c_block_words = '24 soatda 4 marta so\'rov jo\'natishingiz mumkin. \n\nSizni so\'rovingiz limitdan oshdi. 24 soatdan keyin qayta urinib ko\'ring'
23 | c_contact_message = "📥Marhamat murojaatingizni yo'llang:"
24 | c_cancel = '🔙Ortga',
25 | c_create_image = '🖍Rasm chizilmoqda...'
26 | c_send_admin_succsess = '✔Murojjat muaffaqiyatli jo\'natildi, Tez orada javob qaytariladi.'
27 |
--------------------------------------------------------------------------------
/robot/middlewares/throttling.py:
--------------------------------------------------------------------------------
1 | import asyncio
2 |
3 | from aiogram import types, Dispatcher
4 | from aiogram.dispatcher import DEFAULT_RATE_LIMIT
5 | from aiogram.dispatcher.handler import CancelHandler, current_handler
6 | from aiogram.dispatcher.middlewares import BaseMiddleware
7 | from aiogram.utils.exceptions import Throttled
8 |
9 |
10 | class ThrottlingMiddleware(BaseMiddleware):
11 | """
12 | Simple middleware
13 | """
14 |
15 | def __init__(self, limit=DEFAULT_RATE_LIMIT, key_prefix='antiflood_'):
16 | self.rate_limit = limit
17 | self.prefix = key_prefix
18 | super(ThrottlingMiddleware, self).__init__()
19 |
20 | async def on_process_message(self, message: types.Message, data: dict):
21 | handler = current_handler.get()
22 | dispatcher = Dispatcher.get_current()
23 | if handler:
24 | limit = getattr(handler, "throttling_rate_limit", self.rate_limit)
25 | key = getattr(handler, "throttling_key", f"{self.prefix}_{handler.__name__}")
26 | else:
27 | limit = self.rate_limit
28 | key = f"{self.prefix}_message"
29 | try:
30 | await dispatcher.throttle(key, rate=limit)
31 | except Throttled as t:
32 | await self.message_throttled(message, t)
33 | raise CancelHandler()
34 |
35 | async def message_throttled(self, message: types.Message, throttled: Throttled):
36 | if throttled.exceeded_count <= 2:
37 | await message.reply("Too many requests!")
38 |
--------------------------------------------------------------------------------
/robot/handlers/users/contact.py:
--------------------------------------------------------------------------------
1 | from aiogram import types
2 | from aiogram.dispatcher import FSMContext
3 |
4 | from const_texts import c_contact, c_contact_message, c_cancel, c_send_admin_succsess
5 | from loader import dp, bot
6 |
7 | from robot.states.admin_message import Contact
8 | from robot.keyboards.default import make_buttons
9 | from robot.models import Message, TelegramUser
10 | from core.settings import ADMINS_LIST
11 |
12 |
13 | # Echo bot
14 |
15 |
16 | @dp.message_handler(text=c_contact)
17 | async def bot_help(message: types.Message):
18 | await message.answer(
19 | text=c_contact_message
20 | )
21 | await Contact.admin_message.set()
22 |
23 |
24 | @dp.message_handler(state=Contact.admin_message)
25 | async def bot_help(message: types.Message, state: FSMContext):
26 | admin_message = message.text
27 | full_name = message.from_user.full_name
28 | user_id = message.from_user.id
29 | user_name = message.from_user.username
30 | user = await TelegramUser.objects.aget(tg_id=user_id)
31 |
32 | admin_full_message = f"Ismi: {full_name}\n" \
33 | f"User ID: {user_id}\n" \
34 | f"Username: {user_name}\n\n" \
35 | f"Xabar: {admin_message}"
36 |
37 | for admin in ADMINS_LIST:
38 | await bot.send_message(
39 | chat_id=admin,
40 | text=admin_full_message
41 | )
42 |
43 | await bot.send_message(
44 | chat_id=user_id,
45 | text=c_send_admin_succsess,
46 | reply_markup=make_buttons(c_cancel)
47 | )
48 | await Message.objects.acreate(
49 | user=user,
50 | message=admin_message
51 | )
52 |
53 | await state.finish()
54 |
--------------------------------------------------------------------------------
/robot/handlers/users/create.py:
--------------------------------------------------------------------------------
1 | from aiogram import types
2 | from aiogram.dispatcher import FSMContext
3 |
4 | from asgiref.sync import sync_to_async
5 | from .midjourney import draw_picture
6 | from loader import dp, bot
7 | from const_texts import c_create, c_example, c_contact, c_create_description, c_create_image, c_example_get_caption, c_block_words
8 | from robot.states import CreateImage
9 | from robot.keyboards.default import make_buttons
10 |
11 | from robot.models import TelegramUser, Request
12 |
13 | from datetime import datetime, timezone
14 |
15 |
16 | @dp.message_handler(text=c_create)
17 | async def bot_echo(message: types.Message):
18 | await CreateImage.create_image.set()
19 | await message.answer(text=c_create_description)
20 |
21 |
22 | @dp.message_handler(state=CreateImage.create_image)
23 | async def bot_echo(message: types.Message, state: FSMContext):
24 | user = await TelegramUser.objects.aget(tg_id=message.from_user.id)
25 |
26 | input = message.text.lower().strip()
27 |
28 | request_count = await Request.objects.filter(user=user).acount()
29 | if request_count <= 4:
30 | await message.answer(
31 | text=c_create_image
32 | )
33 | result = draw_picture(
34 | input=input
35 | )[0]
36 | await bot.send_photo(
37 | chat_id=message.from_user.id,
38 | photo=result,
39 | caption=c_example_get_caption(input),
40 | reply_markup=make_buttons(
41 | words=[c_create, c_example, c_contact],
42 | row_width=2
43 | )
44 | )
45 | await state.finish()
46 | await sync_to_async(user.set_request_count)()
47 | await Request.objects.acreate(user=user)
48 |
49 | else:
50 | result = None
51 | await message.answer(
52 | text=c_block_words
53 | )
54 | await state.finish()
55 | return
56 |
--------------------------------------------------------------------------------
/robot/handlers/errors/error_handler.py:
--------------------------------------------------------------------------------
1 | import logging
2 | from aiogram.utils.exceptions import (Unauthorized, InvalidQueryID, TelegramAPIError,
3 | CantDemoteChatCreator, MessageNotModified, MessageToDeleteNotFound,
4 | MessageTextIsEmpty, RetryAfter,
5 | CantParseEntities, MessageCantBeDeleted)
6 |
7 |
8 | from loader import dp
9 |
10 |
11 | @dp.errors_handler()
12 | async def errors_handler(update, exception):
13 | """
14 | Exceptions handler. Catches all exceptions within task factory tasks.
15 | :param dispatcher:
16 | :param update:
17 | :param exception:
18 | :return: stdout logging
19 | """
20 |
21 | if isinstance(exception, CantDemoteChatCreator):
22 | logging.exception("Can't demote chat creator")
23 | return True
24 |
25 | if isinstance(exception, MessageNotModified):
26 | logging.exception('Message is not modified')
27 | return True
28 | if isinstance(exception, MessageCantBeDeleted):
29 | logging.exception('Message cant be deleted')
30 | return True
31 |
32 | if isinstance(exception, MessageToDeleteNotFound):
33 | logging.exception('Message to delete not found')
34 | return True
35 |
36 | if isinstance(exception, MessageTextIsEmpty):
37 | logging.exception('MessageTextIsEmpty')
38 | return True
39 |
40 | if isinstance(exception, Unauthorized):
41 | logging.exception(f'Unauthorized: {exception}')
42 | return True
43 |
44 | if isinstance(exception, InvalidQueryID):
45 | logging.exception(f'InvalidQueryID: {exception} \nUpdate: {update}')
46 | return True
47 |
48 | if isinstance(exception, TelegramAPIError):
49 | logging.exception(f'TelegramAPIError: {exception} \nUpdate: {update}')
50 | return True
51 | if isinstance(exception, RetryAfter):
52 | logging.exception(f'RetryAfter: {exception} \nUpdate: {update}')
53 | return True
54 | if isinstance(exception, CantParseEntities):
55 | logging.exception(f'CantParseEntities: {exception} \nUpdate: {update}')
56 | return True
57 |
58 | logging.exception(f'Update: {update} \n{exception}')
59 |
--------------------------------------------------------------------------------
/robot/migrations/0001_initial.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 4.1.4 on 2023-01-11 10:56
2 |
3 | from django.db import migrations, models
4 | import django.db.models.deletion
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | initial = True
10 |
11 | dependencies = [
12 | ]
13 |
14 | operations = [
15 | migrations.CreateModel(
16 | name='Example',
17 | fields=[
18 | ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
19 | ('description', models.TextField(verbose_name='Rasm haqida batafsil')),
20 | ('image', models.ImageField(upload_to='example/', verbose_name='Namuna rasm')),
21 | ('create_date', models.DateTimeField(auto_now_add=True)),
22 | ],
23 | options={
24 | 'verbose_name': 'Example photo',
25 | 'verbose_name_plural': 'Example photos',
26 | },
27 | ),
28 | migrations.CreateModel(
29 | name='Permission',
30 | fields=[
31 | ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
32 | ('name', models.CharField(max_length=100, verbose_name='Ruhsat nomi')),
33 | ('permission_status', models.BooleanField(choices=[(True, 'Ishga tushirish'), (False, "To'xtatish")], default=True, verbose_name='Xolat')),
34 | ],
35 | ),
36 | migrations.CreateModel(
37 | name='TelegramUser',
38 | fields=[
39 | ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
40 | ('full_name', models.CharField(max_length=100, verbose_name='Ismi va familiya')),
41 | ('username', models.CharField(blank=True, max_length=40, null=True, verbose_name='Username')),
42 | ('tg_id', models.CharField(max_length=20, verbose_name='Telegram id')),
43 | ('chat_id', models.CharField(max_length=20, verbose_name='Chat id')),
44 | ('request_all_count', models.IntegerField(default=0, verbose_name="Umumiy so'rovlar soni")),
45 | ],
46 | ),
47 | migrations.CreateModel(
48 | name='Request',
49 | fields=[
50 | ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
51 | ('create_add', models.DateTimeField(auto_now_add=True)),
52 | ('user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='robot.telegramuser', verbose_name='User')),
53 | ],
54 | ),
55 | migrations.CreateModel(
56 | name='Message',
57 | fields=[
58 | ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
59 | ('message', models.TextField(blank=True, null=True, verbose_name='Xabar')),
60 | ('create_add', models.DateTimeField(auto_now_add=True)),
61 | ('user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='robot.telegramuser', verbose_name='User')),
62 | ],
63 | ),
64 | ]
65 |
--------------------------------------------------------------------------------
/robot/models.py:
--------------------------------------------------------------------------------
1 | import datetime as dt
2 | from django.utils.html import mark_safe
3 | from django.db import models
4 | from django.contrib.auth import get_user_model
5 | from asgiref.sync import sync_to_async
6 |
7 | API_NAME = (
8 | ('midjourney', 'Midjourney'),
9 | ('googletrans', 'Googletrans')
10 | )
11 |
12 |
13 | class TelegramUser(models.Model):
14 | full_name = models.CharField(
15 | max_length=100,
16 | verbose_name='Ismi va familiya'
17 | )
18 |
19 | username = models.CharField(
20 | max_length=40,
21 | verbose_name='Username',
22 | null=True,
23 | blank=True,
24 | default='Nomalum'
25 | )
26 |
27 | tg_id = models.CharField(
28 | max_length=20,
29 | verbose_name='Telegram id'
30 | )
31 |
32 | chat_id = models.CharField(
33 | max_length=20,
34 | verbose_name='Chat id'
35 | )
36 |
37 | request_all_count = models.IntegerField(
38 | verbose_name='Umumiy so\'rovlar soni',
39 | default=0
40 | )
41 |
42 | def set_request_count(self):
43 | self.request_all_count += 1
44 | self.save()
45 |
46 | def __str__(self) -> str:
47 | return self.full_name
48 |
49 | def get_user(self):
50 | return self.user
51 |
52 | def set_user(self, user):
53 | self.user = user
54 | self.save()
55 |
56 | def get_username(self):
57 | return mark_safe(f"@{self.username}")
58 |
59 |
60 | class Example(models.Model):
61 | description = models.TextField(
62 | verbose_name="Rasm haqida batafsil"
63 | )
64 |
65 | image = models.ImageField(
66 | upload_to='example/',
67 | verbose_name="Namuna rasm"
68 | )
69 |
70 | create_date = models.DateTimeField(
71 | auto_now_add=True
72 | )
73 |
74 | def __str__(self):
75 | return self.description
76 |
77 | class Meta:
78 | verbose_name = 'Example photo'
79 | verbose_name_plural = 'Example photos'
80 |
81 |
82 | class Request(models.Model):
83 | user = models.ForeignKey(
84 | to=TelegramUser,
85 | on_delete=models.SET_NULL,
86 | verbose_name='User',
87 | null=True,
88 | blank=True
89 | )
90 |
91 | create_add = models.DateTimeField(
92 | auto_now_add=True,
93 | )
94 |
95 | def get_date(self):
96 | return self.create_add.strftime("%H:%M:%S, %d/%m/%Y")
97 |
98 |
99 | class Message(models.Model):
100 | user = models.ForeignKey(
101 | to=TelegramUser,
102 | on_delete=models.SET_NULL,
103 | verbose_name='User',
104 | null=True,
105 | blank=True
106 | )
107 |
108 | message = models.TextField(
109 | verbose_name='Xabar',
110 | blank=True,
111 | null=True
112 | )
113 |
114 | create_add = models.DateTimeField(
115 | auto_now_add=True
116 | )
117 |
118 | def __str__(self):
119 | return f'{self.user} || {self.id} message'
120 |
121 | def get_message(self):
122 | return self.message[:100]
123 |
124 | def get_date(self):
125 | return self.create_add.strftime("%H:%M:%S, %d/%m/%Y")
126 |
127 | def get_username(self):
128 | return self.user.username
129 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # Distribution / packaging
10 | .Python
11 | build/
12 | develop-eggs/
13 | dist/
14 | downloads/
15 | eggs/
16 | .eggs/
17 | lib/
18 | lib64/
19 | parts/
20 | sdist/
21 | var/
22 | wheels/
23 | share/python-wheels/
24 | *.egg-info/
25 | .installed.cfg
26 | *.egg
27 | MANIFEST
28 |
29 | # PyInstaller
30 | # Usually these files are written by a python script from a template
31 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
32 | *.manifest
33 | *.spec
34 |
35 | # Installer logs
36 | pip-log.txt
37 | pip-delete-this-directory.txt
38 |
39 | # Unit test / coverage reports
40 | htmlcov/
41 | .tox/
42 | .nox/
43 | .coverage
44 | .coverage.*
45 | .cache
46 | nosetests.xml
47 | coverage.xml
48 | *.cover
49 | *.py,cover
50 | .hypothesis/
51 | .pytest_cache/
52 | cover/
53 |
54 | # Translations
55 | *.mo
56 | *.pot
57 |
58 | # Django stuff:
59 | *.log
60 | local_settings.py
61 | db.sqlite3
62 | db.sqlite3-journal
63 |
64 | # Flask stuff:
65 | instance/
66 | .webassets-cache
67 |
68 | # Scrapy stuff:
69 | .scrapy
70 |
71 | # Sphinx documentation
72 | docs/_build/
73 |
74 | # PyBuilder
75 | .pybuilder/
76 | target/
77 |
78 | # Jupyter Notebook
79 | .ipynb_checkpoints
80 |
81 | # IPython
82 | profile_default/
83 | ipython_config.py
84 |
85 | # pyenv
86 | # For a library or package, you might want to ignore these files since the code is
87 | # intended to run in multiple environments; otherwise, check them in:
88 | # .python-version
89 |
90 | # pipenv
91 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
93 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
94 | # install all needed dependencies.
95 | #Pipfile.lock
96 |
97 | # poetry
98 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
99 | # This is especially recommended for binary packages to ensure reproducibility, and is more
100 | # commonly ignored for libraries.
101 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
102 | #poetry.lock
103 |
104 | # pdm
105 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
106 | #pdm.lock
107 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
108 | # in version control.
109 | # https://pdm.fming.dev/#use-with-ide
110 | .pdm.toml
111 |
112 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
113 | __pypackages__/
114 |
115 | # Celery stuff
116 | celerybeat-schedule
117 | celerybeat.pid
118 |
119 | # SageMath parsed files
120 | *.sage.py
121 |
122 | # Environments
123 | .env
124 | .venv
125 | env/
126 | venv/
127 | ENV/
128 | env.bak/
129 | venv.bak/
130 |
131 | # Spyder project settings
132 | .spyderproject
133 | .spyproject
134 |
135 | # Rope project settings
136 | .ropeproject
137 |
138 | # mkdocs documentation
139 | /site
140 |
141 | # mypy
142 | .mypy_cache/
143 | .dmypy.json
144 | dmypy.json
145 |
146 | # Pyre type checker
147 | .pyre/
148 |
149 | # pytype static type analyzer
150 | .pytype/
151 |
152 | # Cython debug symbols
153 | cython_debug/
154 |
155 | # PyCharm
156 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
157 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
158 | # and can be added to the global gitignore or merged into this file. For a more nuclear
159 | # option (not recommended) you can uncomment the following to ignore the entire idea folder.
160 | .idea/
--------------------------------------------------------------------------------
/core/settings.py:
--------------------------------------------------------------------------------
1 | """
2 | Django settings for core project.
3 |
4 | Generated by 'django-admin startproject' using Django 4.1.4.
5 |
6 | For more information on this file, see
7 | https://docs.djangoproject.com/en/4.1/topics/settings/
8 |
9 | For the full list of settings and their values, see
10 | https://docs.djangoproject.com/en/4.1/ref/settings/
11 | """
12 |
13 | from pathlib import Path
14 | from environs import Env
15 |
16 | env = Env()
17 | env.read_env()
18 |
19 | # Build paths inside the project like this: BASE_DIR / 'subdir'.
20 | BASE_DIR = Path(__file__).resolve().parent.parent
21 |
22 |
23 | # Quick-start development settings - unsuitable for production
24 | # See https://docs.djangoproject.com/en/4.1/howto/deployment/checklist/
25 |
26 | # SECURITY WARNING: keep the secret key used in production secret!
27 | SECRET_KEY = env.str('SECRET_KEY')
28 |
29 | # SECURITY WARNING: don't run with debug turned on in production!
30 | DEBUG = env.bool('DEBUG', False)
31 | ALLOWED_HOSTS = env.list('ALLOWED_HOSTS')
32 |
33 |
34 | # Application definition
35 |
36 | INSTALLED_APPS = [
37 | 'django.contrib.admin',
38 | 'django.contrib.auth',
39 | 'django.contrib.contenttypes',
40 | 'django.contrib.sessions',
41 | 'django.contrib.messages',
42 | 'django.contrib.staticfiles',
43 | 'robot.apps.RobotConfig',
44 | ]
45 |
46 | MIDDLEWARE = [
47 | 'django.middleware.security.SecurityMiddleware',
48 | 'django.contrib.sessions.middleware.SessionMiddleware',
49 | 'django.middleware.common.CommonMiddleware',
50 | 'django.middleware.csrf.CsrfViewMiddleware',
51 | 'django.contrib.auth.middleware.AuthenticationMiddleware',
52 | 'django.contrib.messages.middleware.MessageMiddleware',
53 | 'django.middleware.clickjacking.XFrameOptionsMiddleware',
54 | ]
55 |
56 | ROOT_URLCONF = 'core.urls'
57 |
58 | TEMPLATES = [
59 | {
60 | 'BACKEND': 'django.template.backends.django.DjangoTemplates',
61 | 'DIRS': [],
62 | 'APP_DIRS': True,
63 | 'OPTIONS': {
64 | 'context_processors': [
65 | 'django.template.context_processors.debug',
66 | 'django.template.context_processors.request',
67 | 'django.contrib.auth.context_processors.auth',
68 | 'django.contrib.messages.context_processors.messages',
69 | ],
70 | },
71 | },
72 | ]
73 |
74 | WSGI_APPLICATION = 'core.wsgi.application'
75 |
76 |
77 | # Database
78 | # https://docs.djangoproject.com/en/4.1/ref/settings/#databases
79 |
80 | DATABASES = {
81 | 'default': {
82 | 'ENGINE': 'django.db.backends.postgresql_psycopg2',
83 | 'NAME': env("DB_NAME"),
84 | 'USER': env("DB_USER"),
85 | 'PASSWORD': env("DB_PASSWORD"),
86 | 'HOST': env("DB_HOST"),
87 | 'POST': env("DB_PORT"),
88 | } if env("DB_TYPE") == 'postgres' else {
89 | 'ENGINE': 'django.db.backends.sqlite3',
90 | 'NAME': BASE_DIR / 'db.sqlite3',
91 | }
92 | }
93 |
94 |
95 | # Password validation
96 | # https://docs.djangoproject.com/en/4.1/ref/settings/#auth-password-validators
97 |
98 | AUTH_PASSWORD_VALIDATORS = [
99 | {
100 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
101 | },
102 | {
103 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
104 | },
105 | {
106 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
107 | },
108 | {
109 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
110 | },
111 | ]
112 |
113 |
114 | # Internationalization
115 | # https://docs.djangoproject.com/en/4.1/topics/i18n/
116 |
117 | LANGUAGE_CODE = 'uz'
118 |
119 | TIME_ZONE = 'Asia/Tashkent'
120 |
121 | USE_I18N = True
122 |
123 | USE_TZ = True
124 |
125 |
126 | # Static files (CSS, JavaScript, Images)
127 | # https://docs.djangoproject.com/en/4.1/howto/static-files/
128 |
129 | STATIC_URL = 'static/'
130 |
131 | STATIC_ROOT = BASE_DIR / 'static'
132 |
133 | MEDIA_URL = 'robot/media/'
134 |
135 | MEDIA_ROOT = BASE_DIR / 'robot/media/'
136 |
137 | # Default primary key field type
138 | # https://docs.djangoproject.com/en/4.1/ref/settings/#default-auto-field
139 |
140 | DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
141 |
142 | BOT_TOKEN = env.str('BOT_TOKEN')
143 |
144 | ADMINS_LIST = env.list('ADMINS_LIST')
145 |
--------------------------------------------------------------------------------