2025, Dec 27 15:04

Снятие ролей пользователя в двух серверах Discord (discord.py)

Пошаговое решение на discord.py: как по id гильдий и ролей снять роли с пользователя в двух серверах Discord. Пример команды, работа с Guild, Role и Member.

Удалить роль у пользователя просто, пока всё происходит в одном сервере. Но как только нужно снять роли с одного и того же пользователя в двух разных серверах, типичные примеры перестают помогать. По сути, задача сводится к тому, чтобы обратиться к нужным объектам Guild по их id, получить соответствующие объекты Role и явно применить изменения к участнику в каждом сервере.

Постановка задачи

Вам нужен бот Discord на discord.py, который снимает с одного пользователя две конкретные роли, причём каждая роль принадлежит своему серверу. Большинство примеров работают только с текущим сервером, где выполняется команда или срабатывает событие, и не показывают, как обращаться к нескольким гильдиям по их id.

Обычный подход для одного сервера (почему его недостаточно)

Типичный шаблон опирается на контекст текущего сервера. Локально он срабатывает, но не затрагивает роли в других серверах.

@app.command()
async def drop_local(ctx, user: discord.Member, role: discord.Role):
    await user.remove_roles(role)
    await ctx.send("Role removed in this server only.")

Этот код снимает роль в том сервере, где выполнена команда. Он не обращается к другим гильдиям и не использует их id для точного указания.

Ключевая идея решения

Чтобы затронуть несколько серверов, нужно явно получить каждую целевую гильдию по её id, затем достать соответствующую роль и членство пользователя в этой гильдии и только после этого вызывать discord.Member.remove_roles. Последовательность такая: получить гильдию по id, взять из неё роль по id, найти пользователя как участника этой гильдии и снять роль. Повторить для второй гильдии.

Рабочее решение: снятие ролей в двух серверах

В примере ниже используются два id гильдий и два id ролей. Обе гильдии получаются через client.get_guild, роли — через guild.get_role, пользователь ищется в каждой гильдии методом guild.get_member, а discord.Member.remove_roles вызывается дважды. Логика минималистична и легко адаптируется под ваши нужды.

@app.command()
async def strip_multi(ctx, target: discord.Member):
    g_a = core.get_guild(<ID>)  # id первой гильдии
    r_a = g_a.get_role(<Role ID>)  # id роли в первой гильдии
    g_b = core.get_guild(<ID>)  # id второй гильдии
    r_b = g_b.get_role(<Role ID>)  # id роли во второй гильдии
    m_a = g_a.get_member(target.id)
    await m_a.remove_roles(r_a)
    m_b = g_b.get_member(target.id)
    await m_b.remove_roles(r_b)
    await ctx.send("Roles are removed from the user.")

Этот сценарий опирается на следующие интерфейсы API: discord.Client.get_guild — чтобы получить сервер по id, discord.Guild.get_role — чтобы найти нужную роль в этом сервере, discord.Guild.get_member — чтобы определить пользователя в этой гильдии, и discord.Member.remove_roles — чтобы снять роль.

Почему это важно

В Discord у объектов есть область видимости. Роль принадлежит конкретной гильдии, и членство пользователя с его ролями тоже привязано к гильдии. Если код ссылается только на текущий контекст, изменения не затронут другие серверы. Явное обращение к обеим гильдиям по id гарантирует, что вы работаете с правильной Role и правильным Member в каждом месте.

Выводы

Когда боту нужно действовать в нескольких серверах, не полагайтесь на неявный контекст. Получите нужную Guild, затем Role и Member внутри этой гильдии и примените изменения. Держите id под рукой, выстраивайте шаги в понятной последовательности и лишь затем вызывайте метод. Приведённый пример специально лаконичен, чтобы его было проще адаптировать под вашу командную структуру и устройство проекта.