【Django】DBに保存した文字列をボタンでコピーする方法

こんにちは、k_ukiです。現在卒業研究でDjangoを用いたwebアプリの開発を行っております。
その中で、ボタンを押すことでその文字列をクリップボードにコピーする機能を実装しました。今回はその実装方法について述べていきます。
![Videotogif (1).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2341225/318d7ab8-a6b7-2975-8973-f29e0c680441.gif)

また、この記事ではオブジェクトを出力する方法（通常のCRUDの処理）やルーティングなどの実装方法は省略いたします。

## テンプレートの作成
以下は、ボタンを配置するページのコードです。
```
{% extends 'base.html' %}
{%block title%}提案結果 {%endblock%}
{% block content %}
<div class="container">
    <div class="row">
        <div class="col-lg-8">
            <h2>提案結果</h2>
            <h3>こちらのワードなどいかがでしょうか？</h3>
            <table>
                <tbody>
                    <!-- ここから -->
                    <!-- ワードを繰り返し出力 -->
                    {% for word in suggest_result %}
                    <tr>
                        <!-- viewに情報を送信するためのフォーム -->
                        <form action="{% url 'search_word' object.pk %}" method="post">
                            {% csrf_token %}
                            <!-- ワードをボタンにして出力（{{word}}に格納） -->
                            <td><input type="submit" name="copy_word" value="{{word}}"></td>
                        </form>
                    </tr>
                    {% endfor %}
                    <!-- 確認用のテキストフィールド（必要はありません） -->
                    <td><input type="text"></td>
　　　　　　　　　　　<!-- ここまで -->
                </tbody>
            </table>
        </div>
    </div>
</div>
{% endblock content %}
```
記述について、一つひとつ解説していきます。
```
{% for word in suggest_result %}
```
ここでは、配列"suggest_result"に格納されたワードを一つずつ"word"に格納して出力できるようにしています。for文をテンプレートに書く際には"{% endfor %}"を忘れずに書きましょう。

```
    <!-- viewに情報を送信するためのフォーム -->
 <form action="{% url 'search_word' object.pk %}" method="post">
    {% csrf_token %}
    <!-- ワードをボタンにして出力（{{word}}に格納） -->
    <td><input type="submit" name="copy_word" value="{{word}}"></td>
 </form>
```
　ここでは、viewに値を送信するためのフォームを作成しています。
　formタグの"action"では、formの送信先を指定しています。ここでは、'search_word'となっていますが、実際は"search_word/:pk"に送信していることになります。また、urlの:pkに該当する部分が"object.pk"になります。"search_word/:pk"というurlはボタンを表示させているページと同じurlになるため、ユーザーから見たら何も起きていないように見えます。
```
{% csrf_token %}
```
　この記述によってcsrfトークンを同時に送信しています。Djangoではフォームを用いる際にはcsrfトークンを同時に送信する必要があります。
```
<input type="submit" name="copy_word" value="{{word}}">
```
　この記述では、コピーしたい文字列が含まれたボタンを生成しています。　
　type="submit" とすることで、入力の形式をsubmitボタンに変更しています。また、submitボタンをクリックした時点でフォームが送信されます。"name"はそのボタンに対する名づけをしており、view側で何をコピーすれば良いか識別するために記述しています。最後に"value"では、ボタンを押下した際に送信したい文字列を指定しています。ここでは、for文で繰り返し出力できるようにしている"word"という変数をしています。
## コピーをするために必要なモジュールをインストールする
　Pythonでクリップボードを操作するために、「pyperclip」と呼ばれる外部モジュールを使用します。このモジュールはPython標準ではないため個別にインストールを行う必要があります。
　pyperclip はpipコマンドでインストール可能です。
```
$ pip install pyperclip
```


## viewで処理を記述する。
```
# views.py
import pyperclip
def detail_func(request, pk):
    #ページを表示させる記述は省略
    .....
    .....
    .....
    if request.method == "POST":
        if "copy_word" in request.POST:
          pyperclip.copy(request.POST["copy_word"])

    .....

```
　view側では、送られてきたリクエストのhttpメソッドが"POST"だった場合の条件分岐をし、その中で実際の処理を記載していきます。
```
if "copy_word" in request.POST:
```
　こちらでは、もし送られてきたPOSTのリクエストの中にcopy_wordという名前のものがあればという条件分岐をしています。"copy_word"とはテンプレート側のinputタグで記載したものです。つまり、この条件分岐によって、送られてきたリクエストがコピーをするものなのかを識別しているということです。
```
pyperclip.copy(request.POST["copy_word"]
```
　ここで、実際コピーを行うためにpyperclipを使用します。pyperclip.copy()を使用することで簡単にクリップボードにコピーを行うことができます。引数に request.POST["copy_word"]を記述することで、送信されてきたPOSTメソッドのリクエストの中でも"copy_word"という名前のvalueを取得することができます。こうすることで、ボタンを押した箇所のvalueが自動的に格納され、その文字列がクリップボードにコピーされるのです。

## さいごに
　以上が、今回私の実装したテンプレートに表示したオブジェクトの文字列をクリップボードにコピーする方法です。今回の実装では、クリップボードにコピーする方法だけではなく、htmlのformタグの仕組みについても詳しく知ることができました！また、views.pyにおけるrequestの用途も知ることができました！！