トップ画像
discord.py 2.4.0でボタンを表示し、匿名投票システムを実現する

執筆者: 瀕死

最終更新: 2025/02/28

discord.py 2.4.0でボタンを表示し、匿名投票システムを実現する

本稿では、Discord上で匿名投票を実現するため、discord.py 2.4.0を用いてボタン(UI要素)を実装する方法について解説します。従来行なわれていた、リアクションによる投票では投票者の情報が把握できてしまう問題がありましたが、本手法ではボタンインタフェースを活用することでその課題を回避します。

背景と目的

匿名投票の必要性

本部活動において最終的な意思決定は部の会員による投票が行われています。しかし従来のリアクション方式では、誰がどのリアクションを行ったかが判別されるため、匿名性を保持した投票が難しいという問題がありました。 そこで、本記事ではdiscord.pyによるボタン表示を活用し、匿名性を確保した投票システムの実装方法を示します。

本記事の概要

本記事では、以下の点について解説します。

  • UI要素の書き方 discord.pyでのボタン作成や表示方法について、具体的なコード例を交えて説明します。

  • ボタン押下時の応答処理 discord.pyの仕様上、interactionに対して必ずresponseを返す必要があるため、毎回のボタン押下に対して応答したくない場合の対処方法(defer()と空白のfollowup()での対応)について記述します。

  • 投票終了後のUI更新 余談として投票が終了した際、初回のUIを含むresponseのhookを利用して投票ボタンを消去する方法について解説します。

  • Koyebでのデプロイ 本システムはKoyeb上でデプロイされています。その点について簡単に触れます。

UI要素の書き方

まず次のようなdiscord.ui.Viewを継承したクラスを作成します。 関数に対応するデコレータをつけることによって対応するUI要素が作成できます。

class VoteView(discord.ui.View):
    @discord.ui.button(label="OK", style=discord.ButtonStyle.success)
    async def ok(self, interaction: discord.Interaction, button: discord.ui.Button):
        # ボタンが押された場合の処理
        await interaction.response.send_message("hoge")
        # もしくは
        # await interaction.response.defer()
        # で応答を数秒間保留できる

    # 後略

そして、このインスタンスを各種send()メソッドで送信すれば利用できます。

@tree.command(name="voteon",description="2択匿名投票の開始")
async def voteyon(interaction: discord.Interaction):
    # 中略

    # 用途は後述する
    global vote_hook
    view = VoteView()
    vote_hook = await interaction.followup.send(content="hogehuga", view=view)

サムネイルのような表示となります。

ボタン押下時の応答処理

discord.pyの仕様では、各interactionに対して必ず何らかのresponseを返す必要があります。しかし場合によっては応答を抑えたいということもあります。 そのような場合はまずdefer()し空のメッセージをもつfollowup.send("")が有効な場合があります。

class VoteView(discord.ui.View):
    @discord.ui.button(label="OK", style=discord.ButtonStyle.success)
    async def ok(self, interaction: discord.Interaction, button: discord.ui.Button):
        await interaction.response.defer()
        # 空メッセージの送信はサーバー側で例外となるが、discord上では目的の動作となる
        # そのため例外を捕捉し何もしない
        try:
            await interaction.followup.send("")
        except discord.HTTPException as e:
            pass

followup.send("")がなければ、discord上で応答がなかった旨のメッセージが生成され、視認性が低下してしまいます。

しかし、このような記述は仕様の変更に敏感であることに注意してください。

投票終了後のUI更新

投票が終了した際、初回のUIを含むresponseのhookを利用して、不要になったボタンを削除することが可能です。

UIを含む送信したメッセージのhookを保持しておいて不要になったらdelete()メソッドで消去することが可能です。

@tree.command(name="endon",description="2択匿名投票の終了と結果表示")
async def endon(interaction: discord.Interaction):
    # 中略
    await vote_hook.delete()

Koyebでのデプロイ

本プロジェクトをKoyebにデプロイしました。これはKoyebが無料プランを提供しているためです。最新の情報や利用条件については、必ず公式ドキュメントを参照してください。

またdiscord developer portalで得られたトークンを.pyファイル記述しないよう気を付けましょう。

まとめ

本記事では、匿名投票システムを実現するために、discord.pyでのボタン表示とその応答処理、さらに投票終了後のUI更新方法、そしてKoyebを利用したデプロイ手順について解説しました。 実装時には、discord.pyの最新の仕様や、デプロイ時の環境設定など、充分に公式の資料を確認してください。

本プロジェクトのリポジトリ

bote-vot https://github.com/hinshiba/bote-vot

参考文献

取得に失敗しました

2024年度 入部