1
2

More than 3 years have passed since last update.

DjangoでDynamoDB、Sessionを使いたい

Last updated at Posted at 2021-07-10

概要

DjangoをSqliteを使わずにDynamoDBだけで実装したいときに役に立ちそうなことを記事にしました。
今回はDjangoからDynamORMを使ってDynamoDBを操作したり、session機能をDynamoDBで実装したりします。

Djangoの設定

まず、以下のライブラリをインストールします。

pip install dynamorm
pip install marshmallow
pip install django-dynamodb-sessions 

今回はセッション情報もDynamoDBに保存します。AWS_ACCESS_KEY_IDなどはAWSIAMで取得してください。

settings.py
#セッションを使うための設定
INSTALLED_APPS = [
    'django.contrib.sessions',
]
MIDDLEWARE = [
    'django.contrib.sessions.middleware.SessionMiddleware',
]
SESSION_ENGINE = 'dynamodb_sessions.backends.dynamodb'

#セッションの有効期間などを設定
SESSION_COOKIE_AGE = 3600
SESSION_EXPIRE_AT_BROWSER_CLOSE = True
SESSION_SAVE_EVERY_REQUEST = True

#AWSのアクセスIDとシークレットIDを追記
DYNAMODB_SESSIONS_AWS_ACCESS_KEY_ID = 'YOUR_AWS_ACCESS_KEY_ID'
DYNAMODB_SESSIONS_AWS_SECRET_ACCESS_KEY = 'YOUR_AWS_SECRET_ACCESS_KEY_ID'
DYNAMODB_SESSIONS_AWS_REGION_NAME = 'ap-northeast-1'
#DynamORMの設定
AWS_ACCESS_KEY_ID = 'YOUR_AWS_ACCESS_KEY_ID'
AWS_SECRET_ACCESS_KEY = 'YOUR_AWS_SECRET_ACCESS_KEY_ID'

DynamoDBの操作

まずmodels.pyで以下のモジュールをインポートしてください。
今回はDynamORMを使用します。

models.py
from dynamorm import DynaModel
from marshmallow import fields

モデルは以下のようにします。
nameに操作したいDynamoDBのテーブル名を、hash_keyにユニークなIDを入れます。

models.py
class SampleTable(DynaModel):
    class Table:
        name = "SmapleTable"
        hash_key = 'SampleId'
        read = 25
        write = 5
    class Schema:
        SampleId = fields.String(required=True)
        name = fields.String()
        age = fields.Number()

ここまででDynamoDBを使う準備ができました。これからは実際に動かしていきます。

操作

では実際にDynamoDBにデータを作成してみます。まず,DyanmoDBのページでSampleTableを作成します。
image.png

次にviews.pyに以下のコードを入れて実行してみます。

views.py
from .models import SampleTable

def index(request):
    s = SampleTable(SampleId="sample1", name="neko", age="21")
    s.save()
    return HttpResponse("Hello, world. You're at the index.")

そしてindexを実行するとDynamoDBにデータが作成されているのが確認できます。
image.png

DynamORMで操作できる一部の例を紹介します。

views.py
from .models import SampleModel

#データ作成
s = SampleModel(id="sample1", name="neko", age="21")
s.save()

#データ取得
s = SampleModel.get(id='sample1')

#データを更新
# partial=Trueを付けない場合他の属性も更新される
s = SampleModel.get(id='sample1')
s.name = "inu"
s.save(partial=True)

#以下の記述でも可能
s.update(name="inu")

DynamORMについて詳しく知りたい方は以下のサイトから

Session

ここまでDynamORMでのデータベース操作を行ってきました。
ここからはsessionの機能をdynamodbで実装していきます。
まず、dynamoDBでセッション用のテーブルsessionsを作成します。プライマリキーはSessionIdに設定しました。

Sessionの保存

request.session.save()がなくても保存されますがこちらのほうがより確実です。

views.py
request.session['Id'] = SampleId
request.session.save()

これを実行すると以下のようにSessionIddataが出てくると思います。
SessionIdにはsession_keyの値が入り、dataにはSampleIdの情報が入っています。
image.png

session_keyの取得

views.py
 session_key = request.session.session_key

データの取得

views.py
 Id = request.session.get('Id')

sessionを削除

views.py
request.session.flush()

sessionに関する他の操作は以下のサイトが役立ちます。
- 【django】sessionの使い方(基本編)

sessionの詳細設定

settings.pyにsessionの詳細設定を追記して反映します。
参考:
- Django でログインセッションの有効期限を設定するのが意外と大変だった
- django-dynamodb-sessions

設定 説明 デフォルト値
DYNAMODB_SESSIONS_TABLE_NAME DynamoDBのテーブル名。  sessions
DYNAMODB_SESSIONS_TABLE_HASH_ATTRIB_NAME sessionテーブルの属性名。 session_key
SESSION_COOKIE_AGE sessionの有効期限を設定 2週間
SESSION_EXPIRE_AT_BROWSER_CLOSE ブラウザを閉じたときにsessionを消す False
SESSION_SAVE_EVERY_REQUEST requestが来るたびにsessionの有効期限をリセット False

使わなくなったSessionを削除

sessionはログアウト時に実行されるrequest.session.flush()によって削除されます。
また、setting.pyに記述した設定によって期限が過ぎた場合などにsessoinは自動的に無効になります。しかし、ログアウトを実行せずにsessionが無効かされた場合はDynamoDBには残り続けます。
自分でいらなくなったsessionDynamoDBから消してもいいですが、DynamoDBTTLという機能を使えば自動的に削除できます。

TTL

TTLというのはDynamoDBのデータを自動的に削除してくれる機能です。DynamoDb概要から設定できます。
今回は後に示すサンプルコードでsessionsExpireTimeという属性を追加しました。
このExpireTimeTTLに監視してもらい、期限を過ぎたら削除してもらいます。
注意点としてはTTLが監視してくれる時間はUNIX時間でないといけません。
image.png

サンプル

実際に動くサンプルコードを用意しました。
このサンプルコードではsessionsテーブルにExpiretimeを追加してTTLを行えるようにしています。
また,htmlを作成していないため動かす際はURLから直接実行してください。

urls.py

urls.py

from django.urls import path

from . import views

urlpatterns = [
    path('', views.index, name='index'),
    path('login', views.login, name='login'),
    path('logout', views.logout, name='logout'),
]

models.py

models.py
from django.db import models
from dynamorm import DynaModel
from marshmallow import fields

class Session(DynaModel):
    class Table:
        name = "sessions" #DyanmoDBのSessionを保存するテーブル名
        hash_key = 'SessionId'#プライマルキー
        read = 25
        write = 5
    class Schema:
        SessionId = fields.String(required=True)
        ExpireTime = fields.Decimal()

views.py

views.py
from django.shortcuts import render
from django.http import HttpResponse
from .models import Session
from datetime import datetime 
from decimal import Decimal
from dateutil.relativedelta import relativedelta

#User name=keita id=1 がいると仮定すると
def index(request):
    return HttpResponse("Hello, world. You're at the index.")

def login(request):
     if request.session.session_key:   
        Id = request.session.get('Id')
        return HttpResponse(f"You're already logined ID={Id}")
    else:
        #sessoinを発行
        request.session['Id'] = 1
        request.session.save()
        #sessionにExpireTime(1か月)を追加
        date_time = Decimal(int((datetime.now()+relativedelta(months=1)).timestamp()))
        s = Session.get(SessionId=request.session.session_key)
        s.update(ExpireTime=date_time)
        s.save(partial=True)
        return HttpResponse("You're Logging")

def logout(request):
    if request.session.session_key:
        request.session.flush()
        return HttpResponse("You're Logout")
    else:
        return HttpResponse("You're not Logging")

python manage.py runserverを実行すると、Hello, world. You're at the index.というページが出てきます。

ログイン 

今回はId=1のユーザーがログインすることを仮定して行います。 今回はパスワードなどはなしで実装しています。
sessionExpireTimeという属性を追加していますが、これは後でsessionを自動的に削除するために必要なものです。
また、request.session.keys()で自分のsessionが存在するか確認できます。返り値はdict_keys(['Id'])のようになっていて、sessionに何が入っているかを確認できます。

views.py
def login(request):
     if request.session.keys():   #ログインしていたら(sessionキーが存在していたら)
        Id = request.session.get('Id')
        return HttpResponse(f"You're already logined ID={Id}")
    else:#ログインしていなかったら
        #sessoinを発行
        request.session['Id'] = 1
        request.session.save()
        #sessionにExpireTime(1か月)を追加
        date_time = Decimal(int((datetime.now()+relativedelta(months=1)).timestamp()))
        s = Session.get(SessionId=request.session.session_key)
        s.update(ExpireTime=date_time)
        s.save(partial=True)
        return HttpResponse("You're Logging")

URLをhttp://127.0.0.1:8000/loginとしてクリックするとYou're Loggingと表示されるはずです。この時DynamoDbのsessionsテーブルを確認すると以下のようになっているはずです。
image.png

もう一度URLをhttp://127.0.0.1:8000/loginを訪問すると、sessionが存在していればYou're already logined ID=1と出てきます。こうなっていれば、ログイン成功です!

ログアウト

views.py
def logout(request):
    #ログインしていればsessionを削除
    if request.session.keys(): 
        request.session.flush()
        return HttpResponse("You're Logout")
    else:
        return HttpResponse("You're not Logging")

では次はhttp://127.0.0.1:8000/logoutを訪問してみます。するとYou're Logoutと出てくると思います。sessionが削除されてログアウトされている状態です。下の画像のようにDynamoDBのsessioinからデータが消えているはずです。
image.png

まとめ

DjangoでDynamoDBを使いたいと思ったときに役に立ちそうなことを書きました。
sessionを使ってログイン機能等を作れると思うので参考になったらうれしいです
何か間違っているところがあったらコメントいただけるとありがたいです。

参考

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2