Ответы пользователя по тегу Python
  • Как правильно сделать декоратор для открытия подключения к базе данных (на основе моего кода с комментариями)?

    @Wolfengo Автор вопроса
    Я ещё зелёный, сильно не душите
    По совету из комментариев, реализовал код вот так:

    import psycopg2.pool
    from psycopg2 import errors
    
    dbname = 'mydatabase'
    user = 'postgres'
    password = '123'
    host = 'localhost'
    port = '5432'
    connection_string = f"dbname={dbname} user={user} password={password} host={host} port={port}"
    
    
    class DatabaseConnection:
        def __init__(self, connection_string):
            self._connection_string = connection_string
            self._connection_pool = psycopg2.pool.SimpleConnectionPool(minconn=1, maxconn=10, dsn=connection_string)
            self._connection = None
    
        def __enter__(self):
            self._connection = self._connection_pool.getconn()
            return self._connection.cursor()
    
        def __exit__(self, exc_type, exc_val, exc_tb):
            if self._connection:
                self._connection.commit()
                self._connection_pool.putconn(self._connection)
    
    
    class PostgreSQLDatabase:
        def __init__(self, connection_string):
            self._connection_string = connection_string
    
        def __enter__(self):
            self._connection = DatabaseConnection(self._connection_string)
            return self._connection.__enter__()
    
        def __exit__(self, exc_type, exc_val, exc_tb):
            return self._connection.__exit__(exc_type, exc_val, exc_tb)
    
    
    class Admin_connected:
        def __init__(self):
            self.database = PostgreSQLDatabase(connection_string)
    
        def create_database_if_not_exists(self):
            # Подключаемся к базе postgres, чтобы узнать, существует ли база
            conn = psycopg2.connect(database='postgres', user=user, password=password, host=host,
                                    port=port)
            conn.autocommit = True
            cursor = conn.cursor()
    
            # Проверка наличия базы данных
            cursor.execute("SELECT 1 FROM pg_database WHERE datname = %s", (dbname,))
            exists = cursor.fetchone()
    
            if not exists:
                try:
                    # Создание новой базы данных
                    with conn.cursor() as cursor:
                        cursor.execute(f"CREATE DATABASE {dbname}")
                        print(f"База данных '{dbname}' создана.")
                        self.create_user_table()
                except Exception as e:
                    print(f'Ошибка {e}')
                finally:
                    if conn:
                        conn.close()
            else:
                print(f"База данных '{dbname}' уже существует.")
    
        def create_user_table(self):
            try:
                with self.database as cursor:
                    cursor.execute(f'CREATE TABLE IF NOT EXISTS public.users '
                                   f"(id integer NOT NULL, user_id integer NOT NULL, PRIMARY KEY (id));"
                                   f'ALTER TABLE IF EXISTS public.users OWNER to postgres;')
                    print(f"[INFO] Таблица пользователей успешно создана")
            except Exception as e:
                print(f'Ошибка при создании новой таблицы: {e}')
    
        def exists(self):
            """Проверяем на наличие в базе данных"""
            try:
                with self.database as cursor:
                    cursor.execute("SELECT * FROM users")
                    print("[INFO] Данные успешно получены")
                    return cursor.fetchall()
            except errors.OperationalError:
                self.create_database_if_not_exists()
                return self.exists()
    
    
    db = Admin_connected()
    print(db.exists())
    Ответ написан
    Комментировать
  • Как избежать повторения функции при получении коложа фотографий?

    @Wolfengo Автор вопроса
    Я ещё зелёный, сильно не душите
    Я нашёл решение этого вопроса. Я сделал так, чтобы через content_types=["text", "photo"]
    бот пересылал медиагруппу вместе с подписью (если не нужно, можно убрать), если 1 фото, то 1 фото с подписью и если текст, то перешлёт текст.

    Долее код подбивайте под ваши нужды

    import asyncio
    from typing import List, Union
    
    from aiogram import Bot, Dispatcher, executor, types
    from aiogram.dispatcher.handler import CancelHandler
    from aiogram.dispatcher.middlewares import BaseMiddleware
    
    bot = Bot(token="")
    dp = Dispatcher(bot)
    
    
    class AlbumMiddleware(BaseMiddleware):
    
        album_data: dict = {}
    
        def __init__(self, latency: Union[int, float] = 0.01):
            self.latency = latency
            super().__init__()
    
        async def on_process_message(self, message: types.Message, data: dict):
            if not message.media_group_id:
                self.album_data[message.from_user.id] = [message]
    
                message.conf["is_last"] = True
                data["album"] = self.album_data[message.from_user.id]
                await asyncio.sleep(self.latency)
            else:
                try:
                    self.album_data[message.media_group_id].append(message)
                    raise CancelHandler()
                except KeyError:
                    self.album_data[message.media_group_id] = [message]
                    await asyncio.sleep(self.latency)
    
                    message.conf["is_last"] = True
                    data["album"] = self.album_data[message.media_group_id]
    
        async def on_post_process_message(self, message: types.Message):
            if not message.media_group_id:
                if message.from_user.id and message.conf.get("is_last"):
                    del self.album_data[message.from_user.id]
            else:
                if message.media_group_id and message.conf.get("is_last"):
                    del self.album_data[message.media_group_id]
    
    
    @dp.message_handler(content_types=['text', 'photo'])
    async def handle_albums(message: types.Message, album: List[types.Message]):
        if not message.media_group_id:
            if message.photo:
                await bot.send_photo(chat_id=message.chat.id, photo=message.photo[-1].file_id, caption=message.caption)
            else:
                await bot.send_message(message.chat.id, message.text)
        else:
            media_group = types.MediaGroup()
            for obj in album:
                if obj.photo:
                    file_id = obj.photo[-1].file_id
                    caption = album[0].caption
                else:
                    file_id = obj[obj.content_type].file_id
    
                try:
                    media_group.attach({"media": file_id, "type": obj.content_type})
                    media_group.media[0]["caption"] = caption
                except ValueError:
                    return await message.answer("Этот тип не поддерживается aiogram.")
    
            await message.answer_media_group(media_group)
    
    
    if __name__ == "__main__":
        dp.middleware.setup(AlbumMiddleware())
        executor.start_polling(dp, skip_updates=True)
    Ответ написан
    Комментировать
  • Создать переменные из массива чтобы оно само создало?

    @Wolfengo
    Я ещё зелёный, сильно не душите
    В программировании нужно сначала гуглить, а потом задавать вопрос :)
    https://ru.stackoverflow.com/questions/900540/Можн...
    Ответ написан
    1 комментарий
  • Telebot, как зная ID сделать ссылку на пользователя?

    @Wolfengo Автор вопроса
    Я ещё зелёный, сильно не душите
    Я нашёл решение через "mem = message.from_user.username", он возвращает имя юзера, если его нету, то None.
    Как я понял, сделать ссылку на контакт (t.me/...) человека не возможно, если у него нет имени юзера, так что это будет, наверное, единственным решением
    Я сделал:
    bot.send_message(***id_admin***,
    f'Покупатель сделал покупку!\n'
    f'Покупатель: @{mem}\n'
    f'Выбор: {last_take_buy[-1]}',
    )
    Ответ написан
    Комментировать