- Djangoで非同期処理を実装するには?
- プルダウンメニューで特定のリストを表示するには?
- Fetch APIの使い方とは?
本記事ではこのような疑問を解決します。
Djangoにおいて、非同期処理でプルダウンメニューを使ったリスト表示をしたい場面ってあると思います。
例えば、プルダウンメニューの商品カテゴリーで「ドリンク」を選択したら、ソフトドリンクやアルコールメニューがパッと表示されるようなシーンです。
このような場合、JavaScriptを使った、Djangoとテンプレート間のデータの受け渡し処理が必要になります。
そこで今回はDjangoにおける非同期処理でプルダウンメニューを使ったリスト表示方法を解説していきます。
前提条件
今回は飲食店での以下のようなメニュー設定を想定します。
○商品カテゴリー
・ドリンク(ソフトドリンク、アルコール)
・パスタ(トマト系ソース、クリーム系ソース)
※・”大”カテゴリー名(”小”カテゴリー名)
○商品
・オレンジジュース(ソフトドリンク)
・ウーロン茶(ソフトドリンク)
・ハイボール(アルコール)
・レモンサワー(アルコール)
・アマトリチャーナ(トマト系ソース)
・ペスカトーレ(トマト系ソース)
・カルボナーラ(クリーム系ソース)
・ポルチーニクリームパスタ(クリーム系ソース)
※・商品名(”小”カテゴリー名)
なお、機能としてはプルダウンメニューで「カテゴリー(大)」を選択すると、選択された「カテゴリー(大)」の中の「カテゴリー(小)」に紐づいた商品(商品名・金額)が一覧で表示されるというものです。
上記のメニュー設定から、models.pyにて以下のモデルを定義します。
from django.db import models
class BigCategory(models.Model):
class Meta:
verbose_name = "カテゴリー(大)"
verbose_name_plural = verbose_name
big_category_id = models.IntegerField(primary_key=True, unique=True)
title = models.CharField(max_length=50)
def __str__(self):
return self.title
class SmallCategory(models.Model):
class Meta:
verbose_name = "カテゴリー(小)"
verbose_name_plural = verbose_name
small_category_id = models.IntegerField(primary_key=True, unique=True)
title = models.CharField(max_length=50)
big_category = models.ForeignKey(BigCategory, on_delete=models.CASCADE)
def __str__(self):
return self.title
class Item(models.Model):
class Meta:
verbose_name = "商品"
verbose_name_plural = verbose_name
item_id = models.IntegerField(primary_key=True, unique=True)
title = models.CharField(max_length=50)
price = models.IntegerField()
small_category = models.ForeignKey(SmallCategory, on_delete=models.CASCADE)
def __str__(self):
return self.title
なお、データベースでのレコードは以下の通りです。
○カテゴリー(大)テーブル
big_category_id | title |
---|---|
1 | “ドリンク” |
2 | “パスタ” |
○カテゴリー(小)テーブル
small_category_id | title | big_category |
---|---|---|
1 | “ソフトドリンク” | 1(”ドリンク”) |
2 | “アルコール” | 1(”ドリンク”) |
3 | “トマト系ソース” | 2(”パスタ”) |
4 | “クリーム系ソース” | 2(”パスタ”) |
○商品テーブル
item_id | title | price | small_category |
---|---|---|---|
1 | “オレンジジュース” | 400 | 1(”ソフトドリンク”) |
2 | “ウーロン茶” | 400 | 1(”ソフトドリンク”) |
3 | “ハイボール” | 500 | 2(”アルコール”) |
4 | “レモンサワー” | 600 | 2(”アルコール”) |
5 | “アマトリチャーナ” | 1200 | 3(”トマト系ソース”) |
6 | “ペスカトーレ” | 1300 | 3(”トマト系ソース”) |
7 | “カルボナーラ” | 1100 | 4(”クリーム系ソース”) |
8 | “ポルチーニクリームパスタ” | 1400 | 4(”クリーム系ソース”) |
バックエンド側の手順
まずはDjangoでの記述をしていきます。
①URLを設定する
urls.pyにてパスを以下のように記述します。
from django.urls import path
from . import views
from django.conf import settings
from django.conf.urls.static import static
app_name = 'app'
urlpatterns = [
path('menu_list', views.menu_list, name='menu_list'),
path('menu_list_info', views.menu_list_info, name='menu_list_info'),
]+ static(settings.STATIC_URL, document_root=settings.STATICFILES_DIRS)
②処理を記述する
views.pyにて、処理を以下のように記述します。
from django.shortcuts import render
from .models import BigCategory, SmallCategory, Item
from django.http import JsonResponse
def menu_list(request):
big_category = BigCategory.objects.all()
item_all = Item.objects.all()
template_name = 'menu_list.html'
context = {
"big_category": big_category,
"item_all": item_all,
}
return render(request, template_name, context)
def menu_list_info(request):
selected_big_category = request.POST.get('big_category')
if selected_big_category == 'all_menu':
item_list = Item.objects.all()
item_list = list(item_list.values())
else:
big_category = BigCategory.objects.get(big_category_id=selected_big_category)
small_category = SmallCategory.objects.filter(big_category=big_category)
item_list = Item.objects.filter(small_category__in=small_category)
item_list = list(item_list.values())
data = {
"item_list": item_list,
}
return JsonResponse(data)
フロントエンド側の手順
こちらではHTMLとJavaScriptの記述を行います。
今回は機能の解説に焦点を当てているため、CSSの記述は省略します。
①テンプレートを作成する
表示するテンプレート(HTML)を以下のように記述します。
<!DOCTYPE html>
{% load static %}
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>メニューリスト</title>
<meta name="description" content="">
</head>
<body>
<main>
<section>
<h1>商品一覧</h1>
<select id="category_select" required>
<option value="すべて" id="all_menu">すべて</option>
{% for b in big_category %}
<option value="{{ b.title }}" id="{{ b.big_category_id }}">{{ b.title }}</option>
{% endfor %}
</select>
<div class="list-container" id="list-container">
{% for item in item_all %}
<div class="product-box">
<div class="product-txt-box">
{{ item.title }}<br>{{ item.price }}円(税込)
</div>
</div>
{% endfor %}
</div>
</section>
</main>
<script src="{% static 'js/menu_info.js' %}"></script>
</body>
</html>
②JavaScriptを記述する
①で作成したHTMLファイルの中で以下のJavaScriptファイルを読み込みます。
// ①Django側にPOST送信する際に記述する"お決まりのコード"
const getCookie = (name) => {
if (document.cookie && document.cookie !== '') {
for (const cookie of document.cookie.split(';')) {
const [key, value] = cookie.trim().split('=');
if (key === name) {
return decodeURIComponent(value);
}
}
}
};
const csrftoken = getCookie('csrftoken');
// ②選択されたセレクトメニュー情報をDjango側にPOST送信してデータを取得する
// セレクトメニュー内の要素を取得する
const categoryList = document.getElementById('category_select');
// セレクトメニューの値が変更された時に実行される処理
categoryList.addEventListener('change', (event) => {
// セレクトメニュー内で選択された値の順番を取得する
const selectedCategoryId = categoryList.selectedIndex;
// セレクトメニュー内で選択された値のidを取得する
const selectedCategory = categoryList[selectedCategoryId].id;
// 非同期処理を記述する
async function menu_list() {
const url = '/menu_list_info';
let res = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8',
'X-CSRFToken': csrftoken,
},
body: `big_category=${selectedCategory}`
});
let json = await res.json();
let item_list = json.item_list;
let list_container = document.getElementById('list-container');
list_container.innerHTML = '';
for (let item of item_list) {
let product_box = document.createElement('div');
let product_txt_box = document.createElement('div');
product_box.className = "product-box";
product_txt_box.className = "product-txt-box";
product_txt_box.innerHTML = `${item.title}<br>${item.price}円(税込)`;
product_box.appendChild(product_txt_box);
list_container.appendChild(product_box);
}
}
// 定義した関数を実行する
menu_list();
});
完成画面を確認
まとめ
以上がDjangoにおける非同期処理でプルダウンメニューを使ったリスト表示方法になります。
イマドキのWebアプリでは動的なWebページが求められており、非同期処理は必須の機能と言えるでしょう。
本記事はDjango×JavaScriptでの非同期処理の基本であるため、様々な開発に応用が可能です。
ぜひあなたのWebアプリ開発に活かしてみてください!
Djangoが学べるプログラミングスクールとは?おすすめのDjangoスクールとは? 本記事ではこのような疑問を解決します。DjangoはPythonで作られた中で1番メジャーなWebフレームワークです。みんなが普段利用するYouT[…]