セッションをデータベースのように使う方法
解決済
回答 2
投稿
- 評価
- クリップ 2
- VIEW 3,589
Djangoでアプリ開発をしています。
非常に基礎的な質問なのだと思いますが、セッションを使って、データベースにおけるテーブルのような形でデータを一時的に保持することはできるのでしょうか。
保存したいテーブルは、「session_id」と「item」の2つです。
一つの「session_id」につき、「item」は複数になりえます。
- セッションを利用しない場合
セッションを利用しないなら、下記の方法で実装できると思います。
# models.py
class Items(models.Model):
session_id = models.CharField(max_length=50) # 各ユーザーのsession_idを格納
item = models.CharField(max_length=50) # 各ユーザーのitemを格納
def __unicode__(self):
return self.item
# views.py
def insert(request, item):
session_id = request.session.session_key # ユーザーのsession_idを取得
items = Items(session_id=session_id, item=item) # Itemsテーブルにsession_idとitemを保存
items.save()
- memcachedを利用する場合
memcachedを利用するとできるのではないかと考え、下記のような記述をしてみました。
import memcache
def insert(request, item):
# session_id = request.session.session_key # ユーザーのsession_idを取得
# items = Items(session_id=session_id, item=item) # Itemsテーブルにsession_idとitemを保存
# items.save()
mc = memcache.Client(['127.0.0.1:11211'])
mc.set('item', item, time=300)
これにより、選んだitemのデータが1つ、300秒間保持できることは確認できました。
しかし、これでは、itemには、1つしかデータを保持できず、一つのsession_idに対し複数のitemを保持させることができません。
再度これを実行すると、洗い替えられてしまいます。
memcacheである必要はありませんので、セッションを利用してこのようなことができる方法はないでしょうか。
なお、セッションを利用したい理由は、データを永続的に保持したくないという理由だけです。
そのため、もし、難しければ、最悪、データベースを使ってデータを保持し、定期的に時間が経ったデータを削除するという実装にしようと考えています。
お分かりの方、ご教示頂ければ幸いです。
よろしくお願いいたします。
-
気になる質問をクリップする
クリップした質問は、後からいつでもマイページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
クリップを取り消します
-
良い質問の評価を上げる
以下のような質問は評価を上げましょう
- 質問内容が明確
- 自分も答えを知りたい
- 質問者以外のユーザにも役立つ
評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。
質問の評価を上げたことを取り消します
-
評価を下げられる数の上限に達しました
評価を下げることができません
- 1日5回まで評価を下げられます
- 1日に1ユーザに対して2回まで評価を下げられます
質問の評価を下げる
teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。
- プログラミングに関係のない質問
- やってほしいことだけを記載した丸投げの質問
- 問題・課題が含まれていない質問
- 意図的に内容が抹消された質問
- 過去に投稿した質問と同じ内容の質問
- 広告と受け取られるような投稿
評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。
質問の評価を下げたことを取り消します
この機能は開放されていません
評価を下げる条件を満たしてません
質問の評価を下げる機能の利用条件
この機能を利用するためには、以下の事項を行う必要があります。
- 質問回答など一定の行動
-
メールアドレスの認証
メールアドレスの認証
-
質問評価に関するヘルプページの閲覧
質問評価に関するヘルプページの閲覧
checkベストアンサー
+3
(リクエストいただきました。)
flied_onionさんとほぼ同じ結論です。
キーを変えないと有効期限も分けられないので、キーを工夫して分けて入れるしかないと思います。
そのキーを管理するオブジェクトだけ無期限で管理するとか、これもflied_onionさんと同じですがセッションに保存しておくとか。
これを実装するとしたら、ロジックが分散して管理しきれなくなる恐れがありますので、それを処理する関数なりクラスなりを作ってまとめて管理させるようにしたほうが良いと思います。
格納する値の形式ですが、直列化可能なオブジェクトなら直接入れても平気かも知れません。以下はdatetime
で試したケースです。
# 他のimportは省略
from datetime import datetime
def index(request):
mc = memcache.Client(['127.0.0.1:11211'])
v = datetime.now()
items = mc.get("items")
print("mc: items = %s" % ", ".join([str(x) for x in items]))
if not items:
items = []
items.append(v)
mc.set("items", items, time=300)
return render(request, "index.html")
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
+3
テーブルというよりは複数件値を入れたいというように見受けました。
memcacheでキーをセッションIDにしていない理由はわかりませんが、
キーをセッションIDにして、値はリストをjson.dumpsを使って、文字列化して格納し、
二回目以降は文字列からリストに戻して加えて、またjson.dumpsしてreplaceするとか、
または key = request.session.session_key + '-001'
のようにセッションIDにインデックスか何かを付加してキーとして(他ユーザーと衝突しないような区切り文字は確認しないとだめですが)、
いくつ保存しているかはセッションに入れておくとか
(getしてNoneなら期限切れの値とする必要もありますが)
といった方法ではどうでしょう?
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
15分調べてもわからないことは、teratailで質問しよう!
- ただいまの回答率 88.09%
- 質問をまとめることで、思考を整理して素早く解決
- テンプレート機能で、簡単に質問をまとめられる
2016/08/11 15:59
リストを利用した下記の実装でうまくいきました。
import memcache
def insert(request, item):
session_key = request.session.session_key
mc = memcache.Client(['127.0.0.1:11211'])
items = mc.get('items') # memcacheから既存のリストを取得
if not items: # 既存のリストが無い場合は、リストを作る
items = []
items.append(item) # 新しいitemをリストに加える
items = list(set(items)) # 重複したitemを整理する
mc.set('items', items, time=30)
return redirect('/')
2016/08/11 16:07
これだとこの処理が30秒間隔を空けないで連続して呼び出された場合、
itemsはずっと消されないことになると思います。
2016/08/11 16:23
今気づいたのですが、ひょっとして、このままだと、ユーザーAが入力して30秒以内にユーザーBが入力した場合も、当初ユーザーAが入力したitemが残り続けてしまいますかね…
開発環境で自分一人で動かしてみただけなので、そこをチェックしていなかったです。
2016/08/11 16:31
keyをsession_keyにしました。
これで、他のユーザーの影響を受けないと思います。
import memcache
def insert(request, item):
session_key = request.session.session_key
mc = memcache.Client(['127.0.0.1:11211'])
items = mc.get(session_key) # memcacheから既存のリストを取得
if not items: # 既存のリストが無い場合は、リストを作る
items = []
items.append(item) # 新しいitemをリストに加える
items = list(set(items)) # 重複したitemを整理する
mc.set(session_key, items, time=30)
return redirect('/')
fried_onionさんが、「キーをセッションIDにしていない理由はわかりませんが」とおっしゃっていた理由が分かりました。
2016/08/11 16:36
session_key = request.session.session_key
mc = memcache.Client(['127.0.0.1:11211'])
items = mc.get(session_key)
という形で受け取っているので、他ユーザーのデータを受け取ることはないと思います。
2016/08/11 17:08
memcachedのキャッシュの中を見たときにsession_keyだけだと
何のデータなのか分かりにくいからです。
あとitemsでない別のデータを同じように処理したいときにも困るので。
あとは、同一セッションの制限時間内にitemsが追加されればOKそうですね。
2016/08/11 17:41