<?xml version="1.0" encoding="utf-8" ?><rss version="2.0" xmlns:tt="http://teletype.in/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:media="http://search.yahoo.com/mrss/"><channel><title>Разработка Telegram-ботов</title><generator>teletype.in</generator><description><![CDATA[В основном рабочие и технические заметки]]></description><image><url>https://img1.teletype.in/files/88/d4/88d4f18b-63c8-4411-970a-b63e163b93bd.png</url><title>Разработка Telegram-ботов</title><link>https://teletype.in/@tgdev</link></image><link>https://teletype.in/@tgdev?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=tgdev</link><atom:link rel="self" type="application/rss+xml" href="https://teletype.in/rss/tgdev?offset=0"></atom:link><atom:link rel="next" type="application/rss+xml" href="https://teletype.in/rss/tgdev?offset=10"></atom:link><atom:link rel="search" type="application/opensearchdescription+xml" title="Teletype" href="https://teletype.in/opensearch.xml"></atom:link><pubDate>Sun, 19 Apr 2026 18:26:03 GMT</pubDate><lastBuildDate>Sun, 19 Apr 2026 18:26:03 GMT</lastBuildDate><item><guid isPermaLink="true">https://teletype.in/@tgdev/HTvs0Ei4EIv</guid><link>https://teletype.in/@tgdev/HTvs0Ei4EIv?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=tgdev</link><comments>https://teletype.in/@tgdev/HTvs0Ei4EIv?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=tgdev#comments</comments><dc:creator>tgdev</dc:creator><title>SQLAlchemy: разница между result.scalars().all()  и result.all()</title><pubDate>Wed, 22 Jan 2025 19:56:18 GMT</pubDate><category>AI Notes</category><tt:hashtag>chatgpt</tt:hashtag><tt:hashtag>python</tt:hashtag><tt:hashtag>orm</tt:hashtag><tt:hashtag>sqlalchemy</tt:hashtag><description><![CDATA[Разница между result.scalars().all() и result.all() заключается в том, как эти методы обрабатывают результат выполнения запроса SQLAlchemy. Они возвращают разные типы данных, что влияет на удобство работы с результатами.]]></description><content:encoded><![CDATA[
  <p id="hKwS">Разница между <code>result.scalars().all()</code> и <code>result.all()</code> заключается в том, как эти методы обрабатывают результат выполнения запроса SQLAlchemy. Они возвращают разные типы данных, что влияет на удобство работы с результатами.</p>
  <hr />
  <h3 id="2Ltu"><strong>1. <code>result.all()</code></strong></h3>
  <ul id="K1tT">
    <li id="bGCB">Возвращает <strong>список кортежей</strong>, где каждый кортеж представляет строку результата запроса.</li>
    <li id="ki57">Используется, если в запросе есть несколько столбцов или вы явно запрашиваете несколько объектов.</li>
  </ul>
  <h4 id="V56L">Пример:</h4>
  <section style="background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <pre id="KTPa" data-lang="python">query = select(UserAdm, ChatAdm).join(Link, Link.user_id == UserAdm.id).join(ChatAdm, Link.chat_id == ChatAdm.id)
result = await session.execute(query)
data = result.all()

print(data)
# [(&lt;UserAdm&gt;, &lt;ChatAdm&gt;), (&lt;UserAdm&gt;, &lt;ChatAdm&gt;)]
</pre>
  </section>
  <p id="RjYr"><strong>Когда использовать</strong>:</p>
  <ul id="7TRX">
    <li id="Rwz8">Когда запрос возвращает несколько объектов или столбцов в строке.</li>
    <li id="FMds">Если нужна информация обо всех возвращённых данных.</li>
  </ul>
  <hr />
  <h3 id="zE4T"><strong>2. <code>result.scalars().all()</code></strong></h3>
  <ul id="14Tf">
    <li id="AL1W">Возвращает <strong>список объектов</strong> из одной конкретной колонки (или объекта), заданной в <code>select()</code>.</li>
    <li id="NlYj">Если вы запрашиваете только один объект или колонку, этот метод &quot;распаковывает&quot; результаты, убирая обёртку кортежей.</li>
  </ul>
  <h4 id="hnGL">Пример:</h4>
  <section style="background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <pre id="ZeWt" data-lang="python">query = select(ChatAdm).join(Link, Link.chat_id == ChatAdm.id)
result = await session.execute(query)
data = result.scalars().all()

print(data)
# [&lt;ChatAdm&gt;, &lt;ChatAdm&gt;]
</pre>
  </section>
  <p id="OphE"><strong>Когда использовать</strong>:</p>
  <ul id="CchI">
    <li id="OcQ2">Когда запрос возвращает один объект или одну колонку.</li>
    <li id="rxsn">Это делает код чище, так как нет необходимости разбирать кортежи.</li>
  </ul>
  <hr />
  <h3 id="TNZx"><strong>Ключевые различия:</strong></h3>
  <p id="tWh6"><strong>Метод:</strong> <code>result.all()</code> <br /><strong>Возвращаемое значение:</strong> Список кортежей (строк результата запроса)<br /><strong>Когда использовать:</strong> Если запрос возвращает несколько объектов или колонок.</p>
  <p id="blGj"><strong>Метод:</strong> <code>result.scalars().all()</code> <br /><strong>Возвращаемое значение: </strong>Список объектов или значений из одной выбранной колонки. <br /><strong>Когда использовать: </strong>Если нужен только один объект или колонка.</p>
  <hr />
  <h3 id="cew3"><strong>Пример для сравнения:</strong></h3>
  <section style="background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <pre id="fxFr" data-lang="python"># Запрос с несколькими столбцами
query = select(UserAdm, ChatAdm).join(Link, Link.user_id == UserAdm.id).join(ChatAdm, Link.chat_id == ChatAdm.id)

result = await session.execute(query)

# Используем result.all()
data_all = result.all()
print(data_all)  # [(&lt;UserAdm&gt;, &lt;ChatAdm&gt;), (&lt;UserAdm&gt;, &lt;ChatAdm&gt;)]

# Используем result.scalars().all()
data_scalars = result.scalars().all()  # Ошибка, так как запрос возвращает несколько столбцов
</pre>
  </section>
  <section style="background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <pre id="qXtH" data-lang="python"># Запрос с одним объектом
query = select(ChatAdm).join(Link, Link.chat_id == ChatAdm.id)

result = await session.execute(query)

# Используем result.all()
data_all = result.all()
print(data_all)  # [(&lt;ChatAdm&gt;,), (&lt;ChatAdm&gt;,)]

# Используем result.scalars().all()
data_scalars = result.scalars().all()
print(data_scalars)  # [&lt;ChatAdm&gt;, &lt;ChatAdm&gt;]
</pre>
  </section>
  <hr />
  <h3 id="xbW8">Резюме:</h3>
  <ul id="HyZO">
    <li id="9Bo2"><strong>Используйте <code>result.scalars().all()</code></strong>, если запрос возвращает <strong>один объект или одну колонку</strong>, так как это упрощает работу с результатами.</li>
    <li id="0ncl"><strong>Используйте <code>result.all()</code></strong>, если запрос возвращает <strong>несколько объектов или колонок</strong>, чтобы сохранить все данные.</li>
  </ul>
  <p id="q8cZ"></p>
  <tt-tags id="DiYp">
    <tt-tag name="chatgpt">#chatgpt</tt-tag>
    <tt-tag name="python">#python</tt-tag>
    <tt-tag name="orm">#orm</tt-tag>
    <tt-tag name="sqlalchemy">#sqlalchemy</tt-tag>
  </tt-tags>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@tgdev/getme</guid><link>https://teletype.in/@tgdev/getme?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=tgdev</link><comments>https://teletype.in/@tgdev/getme?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=tgdev#comments</comments><dc:creator>tgdev</dc:creator><title>Кэширование bot.get_me()</title><pubDate>Mon, 20 Jan 2025 00:52:02 GMT</pubDate><category>AI Notes</category><tt:hashtag>chatgpt</tt:hashtag><tt:hashtag>python</tt:hashtag><tt:hashtag>aiogram</tt:hashtag><description><![CDATA[Метод bot.me() в Aiogram используется для получения информации о самом боте, аналогично вызову bot.get_me(). Однако, главное отличие заключается в том, что bot.me() возвращает закешированное значение, если оно уже было загружено.]]></description><content:encoded><![CDATA[
  <p id="PZdk">Метод <code>bot.me()</code> в Aiogram используется для получения информации о самом боте, аналогично вызову <code>bot.get_me()</code>. Однако, главное отличие заключается в том, что <code>bot.me()</code> <strong>возвращает закешированное значение</strong>, если оно уже было загружено.</p>
  <hr />
  <h3 id="JH1B">Как работает <code>bot.me()</code>?</h3>
  <ol id="Zwmd">
    <li id="XBHE"><strong>Первый вызов <code>bot.get_me()</code></strong>:</li>
    <ul id="UgI3">
      <li id="wbGR">Когда вы вызываете <code>bot.get_me()</code>, Aiogram отправляет запрос в Telegram API на получение информации о боте. Этот запрос возвращает объект <code>aiogram.types.User</code>, содержащий данные о боте (например, <code>id</code>, <code>username</code>, <code>first_name</code>).</li>
    </ul>
    <li id="Ckhr"><strong>Кеширование результата</strong>:</li>
    <ul id="Xy5d">
      <li id="Y4Nr">Aiogram автоматически сохраняет полученный объект в атрибуте <code>bot._me</code>. Это значение сохраняется в памяти до завершения работы приложения.</li>
    </ul>
    <li id="cnE2"><strong>Вызов <code>bot.me()</code></strong>:</li>
    <ul id="mhAg">
      <li id="QF0F">Когда вы вызываете <code>bot.me()</code>, метод проверяет, было ли ранее закешировано значение в <code>bot._me</code>.</li>
      <li id="7w5D">Если значение закешировано, метод возвращает его без нового запроса к Telegram API.</li>
      <li id="2yXM">Если значение отсутствует, <code>bot.me()</code> вызывает <code>bot.get_me()</code> для получения данных, а затем сохраняет результат в <code>bot._me</code>.</li>
    </ul>
  </ol>
  <hr />
  <h3 id="Uckp">Пример использования <code>bot.me()</code></h3>
  <section style="background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <pre id="a4qO" data-lang="python">from aiogram import Bot
from aiogram.types import User

async def get_bot_info(bot: Bot) -&gt; User:
    me = await bot.me()  # Использует закешированное значение или отправляет запрос к Telegram
    return me</pre>
  </section>
  <p id="bnRU">При первом вызове <code>await bot.me()</code>, бот отправит запрос к Telegram, но последующие вызовы вернут закешированное значение, что экономит ресурсы.</p>
  <hr />
  <h3 id="gvyI">Когда использовать <code>bot.me()</code> вместо <code>bot.get_me()</code>?</h3>
  <ul id="967R">
    <li id="Og3b"><strong>Используйте <code>bot.me()</code></strong>, если вам нужно получить информацию о боте несколько раз за сессию.</li>
    <ul id="h7da">
      <li id="I7hH">Например, вы хотите использовать имя или ID бота в разных хендлерах, но эти данные не меняются на протяжении работы приложения.</li>
    </ul>
    <li id="pryD"><strong>Используйте <code>bot.get_me()</code></strong>, если вы хотите быть уверены, что данные о боте актуальны.</li>
    <ul id="zHpD">
      <li id="Njnf">Например, если бот мог быть переименован или поменял username, а вы хотите получить свежие данные (это редкий случай).</li>
    </ul>
  </ul>
  <hr />
  <h3 id="9boC">Как минимизировать количество запросов к Telegram?</h3>
  <p id="9Fjd">Если вы хотите снизить количество запросов, то использование <code>bot.me()</code> — лучший вариант, поскольку:</p>
  <ol id="lvFo">
    <li id="kTwk">Первый запрос сохраняется в кеше.</li>
    <li id="LgKd">Повторные вызовы используют локальное значение.</li>
  </ol>
  <hr />
  <h3 id="huua">Как кешировать данные о боте при старте?</h3>
  <p id="cwVI">Если вы уверены, что данные о боте не изменятся во время работы, вы можете вызвать <code>await bot.me()</code> один раз при старте приложения, чтобы данные оказались закешированными. Например:</p>
  <section style="background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <pre id="NJuP" data-lang="python">async def main():
    bot = Bot(token=TOKEN)
    
    # Закешировать информацию о боте
    await bot.me()
    
    # Теперь любые вызовы bot.me() будут использовать кеш
    ...</pre>
  </section>
  <hr />
  <h3 id="wwH1">Итог</h3>
  <p id="5HQj">Использование <code>bot.me()</code> позволяет эффективно кешировать информацию о боте и уменьшить количество запросов к Telegram API. Если вы хотите ещё больше контроля, можно вызвать <code>await bot.me()</code> один раз при инициализации и использовать этот кеш во всех хендлерах.</p>
  <p id="GAbP"></p>
  <tt-tags id="uJ0X">
    <tt-tag name="chatgpt">#chatgpt</tt-tag>
    <tt-tag name="python">#python</tt-tag>
    <tt-tag name="aiogram">#aiogram</tt-tag>
  </tt-tags>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@tgdev/orm-basic</guid><link>https://teletype.in/@tgdev/orm-basic?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=tgdev</link><comments>https://teletype.in/@tgdev/orm-basic?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=tgdev#comments</comments><dc:creator>tgdev</dc:creator><title>ORM методы</title><pubDate>Sun, 19 Jan 2025 23:41:52 GMT</pubDate><category>AI Notes</category><tt:hashtag>chatgpt</tt:hashtag><tt:hashtag>python</tt:hashtag><tt:hashtag>orm</tt:hashtag><tt:hashtag>sqlalchemy</tt:hashtag><description><![CDATA[Использование ORM-методов в SQLAlchemy предполагает работу с объектами классов (моделей), которые представляют строки таблиц базы данных. Вместо написания SQL-запросов вы работаете с объектами, их атрибутами и методами. Это делает код более читаемым и легко поддерживаемым.]]></description><content:encoded><![CDATA[
  <p id="uekR">Использование ORM-методов в SQLAlchemy предполагает работу с объектами классов (моделей), которые представляют строки таблиц базы данных. Вместо написания SQL-запросов вы работаете с объектами, их атрибутами и методами. Это делает код более читаемым и легко поддерживаемым.</p>
  <h2 id="ILwm">Основные этапы работы с ORM-методами</h2>
  <h3 id="vSZ1">1. Создание и настройка модели</h3>
  <p id="SVd9">Определите модели, которые будут соответствовать таблицам в базе данных. Пример:</p>
  <section style="background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <pre data-lang="python" id="GmAK">from sqlalchemy import Column, Integer, String, ForeignKey
from sqlalchemy.orm import relationship
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()

class User(Base):
    __tablename__ = &quot;users&quot;
    
    id = Column(Integer, primary_key=True)
    username = Column(String, nullable=False)
    email = Column(String, unique=True)</pre>
  </section>
  <h3 id="YKzf">2. Добавление записей</h3>
  <p id="DoqE">Вы создаёте экземпляры классов, заполняете их атрибуты и добавляете в сессию:</p>
  <section style="background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <pre data-lang="python" id="XTGv">async with async_session() as session:
    new_user = User(username=&quot;JohnDoe&quot;, email=&quot;john@example.com&quot;)
    session.add(new_user)
    await session.commit()</pre>
  </section>
  <h3 id="eQac">3. Чтение записей</h3>
  <p id="om0q">Для получения данных вы используете запросы через session.query или session.get:</p>
  <section style="background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <pre data-lang="python" id="AhPH">async with async_session() as session:
    user = await session.get(User, 1)  # Получение пользователя по первичному ключу
    if user:
        print(user.username, user.email)</pre>
  </section>
  <h3 id="gVbP">4. Обновление записей</h3>
  <p id="dfOK">Для обновления записей достаточно изменить атрибуты объекта и вызвать session.commit:</p>
  <section style="background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <pre data-lang="python" id="P36y">async with async_session() as session:
    user = await session.get(User, 1)  # Находим объект
    if user:
        user.email = &quot;new_email@example.com&quot;  # Изменяем атрибут
        await session.commit()  # Сохраняем изменения</pre>
  </section>
  <h3 id="TPmB">5. Удаление записей</h3>
  <p id="PbVt">Для удаления записей используется метод session.delete:</p>
  <section style="background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <pre data-lang="python" id="sJAv">async with async_session() as session:
    user = await session.get(User, 1)  # Находим объект
    if user:
        await session.delete(user)  # Удаляем объект
        await session.commit()  # Сохраняем изменения</pre>
  </section>
  <hr />
  <h3 id="HUDs">Преимущества использования ORM-методов</h3>
  <ul id="rxbh">
    <li id="mBTc">Скрытие SQL-запросов: Нет необходимости вручную писать SQL-код.</li>
    <li id="dgqf">Интуитивность: Вы работаете с объектами Python, что делает код естественным.</li>
    <li id="t0m5">Связи между таблицами: ORM позволяет легко работать с отношениями, например, one-to-many или many-to-many.</li>
  </ul>
  <hr />
  <h3 id="Cipf">Пример сложной операции</h3>
  <p id="E0ko">Допустим, у вас есть пользователь, у которого может быть несколько постов. Нужно добавить новый пост для пользователя:</p>
  <section style="background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <pre data-lang="python" id="ChGS">class Post(Base):
    __tablename__ = &quot;posts&quot;

    id = Column(Integer, primary_key=True)
    title = Column(String, nullable=False)
    content = Column(String, nullable=False)
    user_id = Column(Integer, ForeignKey(&quot;users.id&quot;), nullable=False)

    user = relationship(&quot;User&quot;, back_populates=&quot;posts&quot;)

class User(Base):
    __tablename__ = &quot;users&quot;

    id = Column(Integer, primary_key=True)
    username = Column(String, nullable=False)
    posts = relationship(&quot;Post&quot;, back_populates=&quot;user&quot;)</pre>
  </section>
  <p id="E9um">Добавим пост:</p>
  <section style="background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <pre data-lang="python" id="u4rH">async with async_session() as session:
    user = await session.get(User, 1)
    if user:
        new_post = Post(title=&quot;My First Post&quot;, content=&quot;Hello, world!&quot;, user_id=user.id)
        user.posts.append(new_post)  # Можно работать через &#x60;relationship&#x60;
        await session.commit()</pre>
  </section>
  <hr />
  <h3 id="Jxkp">Рекомендации</h3>
  <ol id="gm7B">
    <li id="ghbO">Работайте через relationship Используйте связи между таблицами (например, user.posts) для упрощения кода.</li>
    <li id="2Hbf">Используйте сессии аккуратно Каждый запрос должен выполняться в пределах асинхронной сессии (async with async_session()).</li>
    <li id="pT0d">Оптимизируйте запросы Если нужно загрузить связанные данные, используйте joinedload или selectinload:</li>
  </ol>
  <section style="background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <pre data-lang="python" id="5Nrl">from sqlalchemy.orm import joinedload

async with async_session() as session:
    user = await session.execute(
        select(User).options(joinedload(User.posts)).where(User.id == 1)
    )
    user = user.scalar_one_or_none()</pre>
  </section>
  <hr />
  <p id="DPVl"></p>
  <tt-tags id="P7yy">
    <tt-tag name="chatgpt">#chatgpt</tt-tag>
    <tt-tag name="python">#python</tt-tag>
    <tt-tag name="orm">#orm</tt-tag>
    <tt-tag name="sqlalchemy">#sqlalchemy</tt-tag>
  </tt-tags>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@tgdev/WyKrUInlOMk</guid><link>https://teletype.in/@tgdev/WyKrUInlOMk?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=tgdev</link><comments>https://teletype.in/@tgdev/WyKrUInlOMk?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=tgdev#comments</comments><dc:creator>tgdev</dc:creator><title>bot: Bot в каждой функции</title><pubDate>Sun, 19 Jan 2025 23:39:30 GMT</pubDate><category>AI Notes</category><tt:hashtag>chatgpt</tt:hashtag><tt:hashtag>python</tt:hashtag><tt:hashtag>aiogram</tt:hashtag><description><![CDATA[Чтобы не передавать объект bot: Bot в каждую функцию, можно создать глобальную переменную и инициализировать её при запуске бота. Этот подход работает, но требует осторожности, так как глобальные переменные могут усложнить тестирование и отладку.]]></description><content:encoded><![CDATA[
  <p id="1mXA">Чтобы не передавать объект bot: Bot в каждую функцию, можно создать глобальную переменную и инициализировать её при запуске бота. Этот подход работает, но требует осторожности, так как глобальные переменные могут усложнить тестирование и отладку.</p>
  <h2 id="ZQIH">Решение с использованием глобальной переменной</h2>
  <h3 id="BKrf">1. Инициализация глобальной переменной bot на уровне файла functions.py:</h3>
  <section style="background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <pre data-lang="python" id="R5wc">from aiogram import Bot

# Глобальная переменная для хранения экземпляра бота
bot: Bot | None = None

def set_bot_instance(bot_instance: Bot):
    &quot;&quot;&quot;
    Устанавливает глобальный экземпляр бота.
    &quot;&quot;&quot;
    global bot
    bot = bot_instance</pre>
  </section>
  <h3 id="ONMi">2. Инициализация в основном файле bot.py:</h3>
  <p id="nZzu">При запуске бота установите экземпляр глобального объекта:</p>
  <section style="background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <pre data-lang="python" id="CkNZ">from aiogram import Bot
from functions import set_bot_instance

async def main():
    bot = Bot(token=TOKEN)
    set_bot_instance(bot)  # Передаём экземпляр бота в functions.py
    ...</pre>
  </section>
  <h3 id="PSPE">3. Использование глобального bot в functions.py:</h3>
  <p id="UVje">Теперь во всех функциях внутри functions.py вы можете обращаться к глобальной переменной bot напрямую:</p>
  <section style="background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <pre data-lang="python" id="1pqu">from aiogram import types
from . import bot  # Импорт глобальной переменной bot

async def send_message_to_user(chat_id: int, text: str):
    &quot;&quot;&quot;
    Отправляет сообщение пользователю.
    &quot;&quot;&quot;
    if bot is None:
        raise RuntimeError(&quot;Bot instance is not initialized!&quot;)
    await bot.send_message(chat_id=chat_id, text=text)</pre>
  </section>
  <h3 id="xbKR">Плюсы подхода:</h3>
  <ol id="ln71">
    <li id="tT71">Уменьшение количества передаваемых аргументов.</li>
    <ul id="fvg2">
      <li id="7tj3">Не нужно передавать bot в каждую функцию.</li>
    </ul>
    <li id="SMmw">Централизованное управление объектом.</li>
    <ul id="e0ZN">
      <li id="eW5g">Экземпляр бота можно легко обновить или заменить, если потребуется.</li>
    </ul>
  </ol>
  <h3 id="0szt">Минусы подхода:</h3>
  <ol id="LxCI">
    <li id="jbLs">Зависимость от глобальной переменной:</li>
    <ul id="cVsR">
      <li id="SDT5">Усложняется тестирование функций, так как нужно явно инициализировать bot перед вызовами.</li>
    </ul>
    <li id="wEts">Потенциальные проблемы с многопоточностью:</li>
    <ul id="RAyA">
      <li id="vbyq">Если ваш код работает в асинхронной среде, использование глобальной переменной может привести к неожиданным ошибкам, если вы одновременно запустите несколько экземпляров бота.</li>
    </ul>
  </ol>
  <h3 id="iCAP">Альтернативный подход: Контекст</h3>
  <p id="BNBR">Если глобальные переменные кажутся неудобными, можно использовать контекст для хранения bot:</p>
  <section style="background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <pre data-lang="python" id="4hZC">from contextvars import ContextVar
from aiogram import Bot

bot_context: ContextVar[Bot] = ContextVar(&quot;bot&quot;)

def set_bot_instance(bot_instance: Bot):
    bot_context.set(bot_instance)
    
def get_bot_instance() -&gt; Bot:
    return bot_context.get()</pre>
  </section>
  <p id="UyeX">Использование:</p>
  <section style="background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <pre data-lang="python" id="jeqy">async def send_message_to_user(chat_id: int, text: str):
    bot = get_bot_instance()
    await bot.send_message(chat_id=chat_id, text=text)</pre>
  </section>
  <p id="lYaO">Этот подход безопаснее для многопоточной среды.</p>
  <p id="iQFo"></p>
  <tt-tags id="pYYY">
    <tt-tag name="chatgpt">#chatgpt</tt-tag>
    <tt-tag name="python">#python</tt-tag>
    <tt-tag name="aiogram">#aiogram</tt-tag>
  </tt-tags>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@tgdev/alembic-basic</guid><link>https://teletype.in/@tgdev/alembic-basic?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=tgdev</link><comments>https://teletype.in/@tgdev/alembic-basic?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=tgdev#comments</comments><dc:creator>tgdev</dc:creator><title>Alembic миграции</title><pubDate>Sun, 19 Jan 2025 23:33:42 GMT</pubDate><category>AI Notes</category><tt:hashtag>chatgpt</tt:hashtag><tt:hashtag>python</tt:hashtag><tt:hashtag>alembic</tt:hashtag><description><![CDATA[Для инициализации данных в таблицах базы данных PostgreSQL с использованием SQLAlchemy и Alembic, рекомендуется использовать Alembic миграции.]]></description><content:encoded><![CDATA[
  <p id="xbQ0">Для инициализации данных в таблицах базы данных PostgreSQL с использованием SQLAlchemy и Alembic, рекомендуется использовать Alembic миграции. Это позволит создавать начальные данные в таблице при выполнении миграций.</p>
  <p id="bjWx">Вот пошаговый подход для добавления первых данных в таблицу:</p>
  <h3 id="GpYS">1. Создайте миграцию с Alembic</h3>
  <p id="yzDa">Используйте команду <code>alembic revision --autogenerate -m &quot;Добавление начальных данных&quot;</code> или создайте новую миграцию вручную:</p>
  <p id="4e96"><code>alembic revision -m &quot;Добавление начальных данных&quot;</code></p>
  <h3 id="UeYB">2. Добавьте код для вставки данных в миграцию</h3>
  <p id="HPv6">В созданном файле миграции найдите функцию upgrade и добавьте SQL-запросы или ORM-операции для вставки данных.</p>
  <p id="Wtqk">Пример файла миграции (<code>&lt;timestamp&gt;_добавление_начальных_данных.py</code>):</p>
  <section style="background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <pre data-lang="python" id="YC3a">from alembic import op
import sqlalchemy as sa

# revision identifiers, used by Alembic.
revision = &#x27;&lt;revision_id&gt;&#x27;
down_revision = &#x27;&lt;previous_revision_id&gt;&#x27;
branch_labels = None
depends_on = None

def upgrade():
    # Добавление начальных данных
    conn = op.get_bind()
    conn.execute(
        sa.text(
            &quot;INSERT INTO settings (key, value) VALUES (:key, :value) ON CONFLICT (key) DO NOTHING&quot;
        ),
        [{&quot;key&quot;: &quot;is_mode_get_user_id&quot;, &quot;value&quot;: &quot;0&quot;},
         {&quot;key&quot;: &quot;get_user_id_message&quot;, &quot;value&quot;: &quot;😶😶😶&quot;}]
    )
    
def downgrade():
    # Удаление данных (опционально, если требуется при откате)
    conn = op.get_bind()
    conn.execute(
        sa.text(&quot;DELETE FROM settings WHERE key IN (:keys)&quot;),
        {&quot;keys&quot;: (&quot;is_mode_get_user_id&quot;, &quot;get_user_id_message&quot;)}
    )

</pre>
  </section>
  <h3 id="xcZ3">3. Обновите базу данных с помощью Alembic</h3>
  <p id="9Qya">Примените новую миграцию, выполнив:</p>
  <p id="6TgJ"><code>alembic upgrade head</code></p>
  <h3 id="Sxw1">Пояснение:</h3>
  <ol id="RZKE">
    <li id="mhSN"><code>conn = op.get_bind()</code>: Получает соединение с базой данных для выполнения SQL-запросов напрямую.</li>
    <li id="cPTp"><code>ON CONFLICT (key) DO NOTHING</code>: PostgreSQL-конструкция для игнорирования ошибок вставки, если запись с таким ключом уже существует (аналогично <code>INSERT OR IGNORE</code> в SQLite).</li>
    <li id="zCjk">Использование <code>sa.text</code>: Позволяет вставлять данные через сырые SQL-запросы с поддержкой параметров.</li>
  </ol>
  <h3 id="v8rU">Альтернативный подход через ORM (опционально)</h3>
  <p id="r2zF">Если вы хотите использовать SQLAlchemy ORM вместо сырых SQL-запросов, можно выполнить инициализацию в отдельном скрипте, используя сессию:</p>
  <section style="background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <pre data-lang="python" id="UNiy">from sqlalchemy.orm import Session
from your_project.models import Setting  # Импортируйте вашу ORM-модель

def initialize_settings(engine):
    with Session(engine) as session:
        # Проверяем, есть ли записи, и добавляем только если они отсутствуют
        if not session.query(Setting).filter(Setting.key == &quot;is_mode_get_user_id&quot;).first():
            session.add(Setting(key=&quot;is_mode_get_user_id&quot;, value=&quot;0&quot;))
        if not session.query(Setting).filter(Setting.key == &quot;get_user_id_message&quot;).first():
            session.add(Setting(key=&quot;get_user_id_message&quot;, value=&quot;😶😶😶&quot;))
        session.commit()</pre>
  </section>
  <h3 id="iZ4t">Рекомендации:</h3>
  <ol id="D0JS">
    <li id="vH8p">Для разового выполнения начальной инициализации используйте Alembic миграции.</li>
    <li id="l2AY">Если данные должны проверяться и обновляться динамически, создайте отдельную функцию для инициализации, как в примере с ORM.</li>
  </ol>
  <p id="DmcE">Использовать Alembic или ORM для внесения начальных данных возможно, и оба подхода имеют свои плюсы. Вот детальное руководство для обоих случаев.</p>
  <h3 id="5Li8">1. Внесение данных через Alembic</h3>
  <p id="UTgq">В миграциях Alembic вы можете использовать SQLAlchemy ORM для работы с таблицами.</p>
  <p id="l0zj">Пример файла миграции (<code>&lt;timestamp&gt;_добавление_данных.py</code>):</p>
  <section style="background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <pre data-lang="python" id="UPfE">from alembic import op
from sqlalchemy.orm import Session
from sqlalchemy import inspect
from your_project.models import Settings  # Импортируйте вашу модель Settings

# revision identifiers, used by Alembic.
revision = &#x27;&lt;revision_id&gt;&#x27;
down_revision = &#x27;&lt;previous_revision_id&gt;&#x27;
branch_labels = None
depends_on = None

def upgrade():
    # Получение текущей сессии
    bind = op.get_bind()
    session = Session(bind=bind)
    # Проверка существования таблицы (опционально)
    inspector = inspect(bind)
    if &#x27;settings&#x27; in inspector.get_table_names():
        # Вставка данных, если таблица существует
        settings = [
            Settings(key=&#x27;is_mode_get_user_id&#x27;, value=&#x27;0&#x27;),
            Settings(key=&#x27;get_user_id_message&#x27;, value=&#x27;😶😶😶&#x27;),
        ]
        for setting in settings:
            # Убедитесь, что данные добавляются только при отсутствии
            if not session.query(Settings).filter_by(key=setting.key).first():
                session.add(setting)
        session.commit()
        
def downgrade():
    # Откат: удаление данных
    bind = op.get_bind()
    session = Session(bind=bind)
        session.query(Settings).filter(
        Settings.key.in_([&#x27;is_mode_get_user_id&#x27;, &#x27;get_user_id_message&#x27;])
    ).delete(synchronize_session=False)
    session.commit()    </pre>
  </section>
  <h4 id="SkRX">Пояснения:</h4>
  <ol id="OUGR">
    <li id="cNKQ"><code>Session(bind=bind)</code>: Создаёт сессию на основе текущего соединения Alembic.</li>
    <li id="1Tx1">Проверка на существование таблицы: Это полезно, если вы не уверены, что таблица уже создана.</li>
    <li id="GRyY">Проверка существующих записей: Гарантирует, что данные не будут добавлены повторно, если миграция выполняется несколько раз.</li>
  </ol>
  <h3 id="hIcX">2. Внесение данных через ORM</h3>
  <p id="ht2r">Этот метод подходит, если вы хотите вставить данные в таблицу в вашем основном коде приложения.</p>
  <h4 id="VkDg">Пример:</h4>
  <section style="background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <pre data-lang="python" id="U0oS">from sqlalchemy.orm import Session
from your_project.models import Settings
from sqlalchemy import create_engine
from your_project.database import Base  # где инициализируется ваш Base

# Создаём подключение к базе данных
engine = create_engine(&quot;postgresql+psycopg2://username:password@localhost/dbname&quot;)

def initialize_settings():
    with Session(engine) as session:
        # Добавляем данные, если они ещё не существуют
        if not session.query(Settings).filter_by(key=&quot;is_mode_get_user_id&quot;).first():
            session.add(Settings(key=&quot;is_mode_get_user_id&quot;, value=&quot;0&quot;))
        if not session.query(Settings).filter_by(key=&quot;get_user_id_message&quot;).first():
            session.add(Settings(key=&quot;get_user_id_message&quot;, value=&quot;😶😶😶&quot;))
        session.

# Вызываем функцию инициализации
if __name__ == &quot;__main__&quot;:
    initialize_settings()</pre>
  </section>
  <h3 id="BAKm">Что выбрать?</h3>
  <ul id="jpqe">
    <li id="H6xM">Alembic миграции: Если данные должны быть добавлены вместе с обновлением структуры базы данных. Это лучший подход для контроля версий.</li>
    <li id="1X1j">ORM: Если данные должны добавляться в рантайме, например, при первом запуске приложения.</li>
  </ul>
  <h3 id="Xbaf">Комбинированный подход:</h3>
  <p id="Ns95">Если вы используете Alembic для структуры таблиц, но хотите более гибкий способ добавления данных, используйте Alembic с ORM в одном из миграционных скриптов, как показано в первом примере.</p>
  <p id="ZUNk"></p>
  <tt-tags id="92YZ">
    <tt-tag name="chatgpt">#chatgpt</tt-tag>
    <tt-tag name="python">#python</tt-tag>
    <tt-tag name="alembic">#alembic</tt-tag>
  </tt-tags>

]]></content:encoded></item></channel></rss>