Djangoのセッション管理
Djangoの request.session
は、ユーザー固有のセッションデータを辞書のように扱い、セッションを介して状態情報を保持するための仕組みです。これを使うことで、ユーザーのブラウザ間で状態を維持し、複数のリクエストをまたいでデータを保持できます。以下は週刊少年ジャンプのワンピースを例に使ってます。
セッションデータの保存と取得方法
保存方法
セッションデータは、キーと値のペアとして request.session
に保存します。たとえば、検索条件などをセッションに保存する場合は以下のように書きます。
self.request.session['wanted_search_data'] = self.request.GET.copy()
これは、ユーザーからの GET リクエストに含まれる検索条件をそのままセッションにコピーして保存する例です。
取り出し方法
セッションからデータを取り出すには、指定したキーを使います。
wanted_search_data = self.request.session.get('wanted_search_data', None)
このコードは、セッションに保存された検索データを取得し、存在しない場合は None
を返します。
クラスベースビューのカスタマイズ例
以下では、賞金首(Wanted Posters)の一覧を管理する WantedPosterListView
を例に、セッションを活用した検索条件の保持方法を示します。
ビューの定義
class WantedPosterListView(ListView):
template_name = 'wantedposters_list.html'
model = WantedPosters
context_object_name = 'wanted_posters'
paginate_by = 20
-
ページネーション (
paginate_by
)
1ページあたり20件の賞金首を表示します。
GETリクエストのハンドリング
def get(self, request, *args, **kwargs):
if not request.GET:
# セッションから検索データを取得
wanted_search_data = request.session.get('wanted_search_data', None)
if wanted_search_data:
# セッションにデータがある場合は、そのデータを使ってリダイレクト
query = f"?{urlencode(wanted_search_data)}"
url = reverse('wantedposter_list') + query
return HttpResponseRedirect(url)
else:
# セッションにデータがない場合はデフォルトパラメータを設定
query = "?pirate_name=&crew_name=&devil_fruit=&period_before=on&period_during=on&period_undefined=on"
url = reverse('wantedposter_list') + query
return HttpResponseRedirect(url)
return super().get(request, *args, **kwargs)
-
検索パラメータが空の場合
セッションに保存された検索条件があればそれをクエリとして付け、なければデフォルトの検索条件を使ってリダイレクトしています。
クエリセットのカスタマイズ
def get_queryset(self):
form = WantedSearchForm(self.request.GET or None)
if form.is_valid():
# 検索条件をセッションに保存
self.request.session['wanted_search_data'] = self.request.GET.copy()
else:
# フォームが不正または無い場合、セッションのデータをフォームに復元
initial_data = self.request.session.get('wanted_search_data', {})
form = WantedSearchForm(initial_data)
queryset = WantedPosters.objects.all().order_by(*self.ordering)
today = timezone.now().date()
if form.is_valid():
filters = form.cleaned_data
# 名前や所属クルーなどのテキスト検索
if filters.get('pirate_name'):
queryset = queryset.filter(name__icontains=filters['pirate_name'])
if filters.get('crew_name'):
queryset = queryset.filter(crew__name__icontains=filters['crew_name'])
if filters.get('devil_fruit'):
queryset = queryset.filter(devil_fruit__icontains=filters['devil_fruit'])
# 日付に基づくフィルタリング
query = Q()
if filters.get('period_before'):
query |= Q(issue_date__gt=today)
if filters.get('period_during'):
query |= Q(issue_date__lte=today, expiry_date__gte=today)
if filters.get('period_after'):
query |= Q(expiry_date__lt=today)
if filters.get('period_undefined'):
query |= Q(issue_date__isnull=True) | Q(expiry_date__isnull=True)
queryset = queryset.filter(query)
return queryset.distinct()
-
検索フォーム (
WantedSearchForm
)
ユーザーが入力した検索条件に基づき、賞金首データをフィルタリングします。 -
セッションとの連携
検索条件をセッションに保存し、フォーム再生成の際に復元することで、ページ遷移しても条件を維持します。
コンテキストデータの追加
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
initial_data = self.request.session.get('wanted_search_data', {
'period_before': True,
'period_during': True,
'period_undefined': True,
'period_after': False
})
context['form'] = WantedSearchForm(initial=initial_data)
wanted_posters = context['wanted_posters']
# 発行日や期限日をフォーマット
for poster in wanted_posters:
poster.formatted_issue_date = poster.issue_date.strftime('%Y/%-m/%-d') if poster.issue_date else None
poster.formatted_expiry_date = poster.expiry_date.strftime('%Y/%-m/%-d') if poster.expiry_date else None
return context
-
フォームに初期値をセット
セッションに保存された検索条件を読み込み、フォームの初期値として設定します。 -
日付の表示形式を変更
テンプレートで扱いやすいように、発行日や期限日をフォーマットして渡しています。
まとめ
- Djangoのセッション機能を使うと、ユーザーが入力した検索条件などを継続的に保持できます。
- クラスベースビューでは、
get_queryset
でフォームの入力内容をセッションに保存し、get
メソッドやget_context_data
で適宜セッションデータを利用する構成が便利です。 - 賞金首一覧の例のように、フィルタ条件を継続的に保持しながらページングや再検索を行う場面で役立ちます。