ユーニックス総合研究所

  • home
  • archives
  • django-cookie

DjangoのCookieの取得・保存方法(COOKIES, set_cookie)

  • 作成日: 2021-08-17
  • 更新日: 2023-12-24
  • カテゴリ: Django

Djangoのcookieの取得・保存方法

DjangoではCookie(クッキー)を扱うことが出来ます。
Cookieはクライアントサイドでも利用できる一時的なデータ保存領域のことで、これを使うとサイトに状態を持たせることが可能です。

Cookieにサイトのクリティカルなデータを保存するのは危険ですが、一時的な重要でないデータを保存するにはCookieはうってつけです。
この記事ではDjangoでCookieを取得・保存する方法について解説したいと思います。
具体的には↓を見ていきます。

  • Cookieとは?
  • DjangoでCookieを取得する
  • DjangoでCookieを保存する
  • クライアントサイド(JavaScript)でCookieを利用する

Cookieとは?

Cookie(クッキー)とはブラウザでWebサイトにアクセスした際に、ブラウザが作成するファイルのことを言います。
このファイルにはWebサイトが指定した情報などが保存されます。
ユーザーはこのファイルを利用することで、ステートレスなHTTPで状態を持った通信を行うことが出来ます。
たとえばECサイトのショッピング・カートの情報などです。カートの情報は別のページに移動した際にも保存されている必要がありますが、こういった状態を持ったロジックにはCookieやセッションなどが使われます。

Cookieはユーザーが自由に削除することが出来ます。そのため揮発的なデータと言えます。
また、Cookieはユーザーが自由に閲覧することが出来るため、Webサイトにとってクリティカルで重要なデータを保存するのには向いていません。
あくまで一時的で、重要でないデータを保存するのにCookieは使われます。
ショッピングカートで言えば、商品のIDなどがそうです。これらのIDは流出しても問題がないと見なされて、Cookieに保存されることがあります。

DjangoでCookieを取得する

DjangoでCookieを取得するには、requestからCOOKIESを参照します。
このCOOKIESは辞書風のオブジェクトで、get()メソッドなどで値を取得することが出来ます。
たとえばcountという名前のCookieの値を取得するには↓のようにします。

def home_view(request):  
    ...  
    count = request.COOKIES.get('count', 0)  
    ...  

↑の場合、countには0かあるいは既存のcountの値が入ります。
get()メソッドは第1引数のキーの値を取得しますが、第2引数にはそのキーが存在しなかった場合のデフォルト値を指定することが出来ます。

なぜクライアントサイドで参照されるCookieがサーバーサイドで取得できるのか?

Cookieはブラウザに保存されるものですが、HTTP通信の時にCookieヘッダーというヘッダーにクッキーがセットされます。
このヘッダーはサーバーサイドで解析することが可能です。
そのためDjangoもこのヘッダーを解析して、COOKIESに値を保存しているということになります。

ちなみにCOOKIESWSGIRequestのプロパティです。
このWSGIRequestdjango/core/handlers/wsgi.pyから参照することが出来ます。
COOKIES@cached_propertyでデコレートされたプロパティで、内部では環境からHTTP_COOKIEという生のCookieを取り出し、それをparse_cookie()という関数でパースしています。その結果がCOOKIESの返す値です。

DjangoでCookieを保存する

DjangoでCookieを保存するにはレスポンスのメソッドset_cookie()を使います。

def simple_view(request):  
    response = HttpResponse()  
    response.set_cookie('count', 1)  
    return response  

↑の場合、レスポンスのCookieにはcount=1がセットされます。

set_cookie()の構造

set_cookie()は↓のような構造になっています。

def set_cookie(self, key, value='', max_age=None, expires=None, path='/',  
               domain=None, secure=False, httponly=False, samesite=None)  

set_cookie()は内部ではcookiesというクラスの属性にCookieを保存します。
このcookiesSimpleCookieというオブジェクトで、これはdjango/http/cookie.pyから参照することが出来ます。

expiresの値は以下の値である必要があります。

  • 文字列(正しい日付のフォーマット)
  • ナイーブ(naive)なdatetime.datetimeオブジェクト(UTC)
  • アウェア(aware)なdatetime.datetimeオブジェクト(いずれかのタイムゾーン)
  • (もしdatetime.datetimeであればmax_ageを計算します)

naiveawareについては↓に詳しく書かれています。

Aware オブジェクトと Naive オブジェクト - datetime --- 基本的な日付型および時間型 — Python 3.9.4 ドキュメント

簡単に言うとnaiveはタイムゾーンなどの時間情報を持たないオブジェクトです。
いっぽうawareはタイムゾーンや夏時間情報などを持ちます。
これらのオブジェクトは属性tzinfoNoneならnaiveに、それ以外はawareになります。

クライアントサイド(JavaScript)でCookieを利用する

サーバーサイドで設定したCookieをクライアントサイドで参照したい場合は↓のようなコードを書きます。

from django.http import HttpResponse  


def home_view(request):  
    response = HttpResponse('''  
        <script>  
            let cookies = document.cookie.split(';')  
            for (const c of cookies) {  
                const kv = c.split('=')  
                if (kv[0].replace(/^\s+/g, '') === 'count') {  
                    document.write(kv[1])  
                }  
            }  
        </script>  
    ''')  
    count = request.COOKIES.get('count', 0)  
    count = int(count) + 1  
    response.set_cookie('count', count)  
    return response  

↑のビューは、まず<script>タグを含んだレスポンスを生成します。
その後にCOOKIESを参照してcountを取得します。
そしてcountの値を1増やして、set_cookieでレスポンスにCookieをセットします。
最後にそのレスポンスを返します。

<script>タグ内ではdocument.cookieの値を参照しています。
これは生のCookieなので目的の値を取り出すにはパースが必要です。
そのため↑のようにfor文などを回してcountの値を取り出すようにしています。

↑のビューを実行すると、画面にcountの値が表示されます。
そしてブラウザを更新するたびに値が増えていきます。

おわりに

今回はDjangoのCookieを見てみました。
Cookieはよく使われるツールの1つですが、Djangoでは簡単に扱うことが可能です。

🦝 < クッキーが一枚、クッキーが二枚

🐭 < あれ? 一枚足りないな