deta.spaceにデータベースを作る
deta.spaceはプログラムを作るだけでなく、データベースを作ることができます。Baseという名前がついています。
このBaseと他のデータベースとの違いは、NoSQLだということです。
NoSQLとは
今までの授業の中では、SQLの重要性を説き、いかにSQLを覚えるかに重点を置いてきました。ここでいうNoSQLとは、Not Only SQLの略でSQLを使わないでデータベースを扱うRDB以外のデータベースです。
処理速度、拡張性は優れていますが、検索が弱いといわれています。
RDBではリレーションを実行時に行いますが、NoSQLでは設計時に行うしかないようです。
Baseとはどんなデータベースか
BaseとはRDBではなく、ドキュメント指向型データベースで、要はJSONのようなものです。pythonの型の辞書型にランダムなKeyがくっついたようなものです。ドキュメント指向型DBで有名なのはMondoDBで世界で5番目にユーザーが多いようです。
テーブルをつくるには
deta.spaceはdeta.shと違って、テーブルやその中身を手動で作るGUIがあります。canvasからcollectionsをクリックします。
最初は空っぽなのでこのような画面がでます。「Get start」してください
そしてdriveを作るのかBaseを作るのか聞いてきます。今回はBaseです。
collection名を聞いてくるので「basesample」としました。
続いてbaseの名前を入れます。今回は「my_items」です
空っぽのbaseがでるのでまずは「add item」でキーを作成します。そしてエンピツのアイコンをクリック
itemの中身を追加して、「save item」します。
今入れたデータが保存されています
Baseをプログラムで作ってみよう
これでは、面倒なのでプログラムでつくることもできます。ただしその前にこのcollectionに対するdata keyを取得する必要があります。「collection settimgs」をクリックします。
「create new data key」を押します
「generate」をクリックします
40桁位のdata keyが作成されて表示されます。これは2度と表示されないのでここで保存してください。あとで使います。
普通にprojectを作ります。今回は「createbasetest」にしました。そのフォルダーを作って移動してからコマンドを入力します
space login space new
ここからプログラムを作成していきます。ただし、実行はできるのですが意味不明のエラーが出ます。
main.app
from deta import Deta
deta = Deta("create keyで作成したbase key 40桁くらい")
db1 = deta.Base("makers")
db1.put({"id": 1, "name": "山田さん", "address": "鹿児島市中央町","tel": "099-123-4567"})
db1.put({"id": 2, "name": "斉藤さん", "address": "鹿児島市紫原2丁目","tel": "099-234-5678"})
db1.put({"id": 3, "name": "川上さん", "address": "鹿児島市吉野町","tel": "099-345-6789"})
db2 = deta.Base("my_items")
db2.put({"id": 1, "maker_id": 1,"item_name": "いちご","price": 180,"keyword":["赤い","甘い","ケーキ"],"created":"2022-10-21"})
db2.put({"id": 2, "maker_id": 2,"item_name": "りんご","price": 90,"keyword":["丸い","赤い","パイ"],"created":"2022-10-22"})
db2.put({"id": 3, "maker_id": 1,"item_name": "バナナ","price": 120,"keyword":["パック","甘い","黄色"],"created":"2022-10-23"})
db2.put({"id": 4, "maker_id": 3,"item_name": "ブルーベリー","price": 200,"keyword":["袋入り","青い","眼精疲労"],"created":"2022-10-24"})
db3 = deta.Base("carts")
db3.put({"id": 1, "item_id": 1, "count": 5})
db3.put({"id": 2, "item_id": 2, "count": 3})
db3.put({"id": 3, "item_id": 3, "count": 1})
db3.put({"id": 4, "item_id": 1, "count": 3})
db3.put({"id": 5, "item_id": 3, "count": 2})
db3.put({"id": 6, "item_id": 1, "count": 3})
さきほど作成したdata keyを Deta に与えてあげればオブジェクトが作成されます。このdata keyはgenerate作成時1回しか表示されないもので、あとからは表示できませんのでかならずMEMOしてください。
その作られたオブジェクトにobject.Base("Base名")で作成できます。そして作成したいデータを辞書型でputしてあげれば保存されます。
今回はphpの教科書「マイナビ よくわかるPHPの教科書」に出てくるサンプルのテーブルと同じものを作りました。ただkeywordのところはphpではカンマ区切りの文字列として保存していましたが、リストとして保存しました。このようにカラムの中に配列が保存できるのがNoSQLの面白いところです
requirements.txtにはdetaを入れます
requirements.txt
deta
SpaceFileも作ります
SpaceFile
# Spacefile Docs: https://go.deta.dev/docs/spacefile/v0 v: 0 micros: - name: createbasetest src: ./ engine: python3.9 primary: true public: true
実行方法は、まずはproject登録するので push
space push
canvasにprojectが登録されたら実行します。エラーが出ます。次が変なのですが、いくらbaseを作ってもそのままでは表示されません。これでかなり迷いました。なんと表示するように追加しないといけない。この「+」をクリックします
そして「open exists base」を選び、候補にチェックを入れて「open selected」をクリックします。
編集や削除ができます。
クエリーを動かしてみる
baseのなかでクエリーをかけることができます。たとえばmy_itemsでidが1のものを探すには
と入力して「run query」すると
のように絞り込まれます。クエリーを全部消せば、また全部出てきます。
いちごを探す item_name:"いちご" 甘いを含むものを探す "keyword?contains":"甘い" 2022-10-22より後の日 "created?gt";:"2022-10-22" 2022-10-22より後の日でかつ値段が180より小さいもの "created?gt":"2022-10-22","price?lt":180
このようにSQLのようなクエリーを実行することができます
Basesを利用したMicroの作成
Baseにはphpの教科書で使ったデータベースを入れてありますので、phpと同じように、まずは一覧表示を作ってみましょう。
mkdir dir_myitems cd dir_myitems space login space new
main.py
from flask import Flask, render_template
from deta import Deta
app = Flask(__name__)
#リスト作成
# myitems = [{"id":1,"maker_id":1, "item_name":"いちご","price":180}]
#データベース読込
deta = Deta("data key")
myitems = deta.Base("my_items")
@app.route('/')
def index():
itemsdata = myitems.fetch(query=None)
allitems = itemsdata.items
allitems = sorted(allitems,key=lambda x: x['id'])
return render_template('index.html', data = allitems)
/templates/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC"
crossorigin="anonymous">
<title>商品一覧</title>
</head>
<body>
<div class="container">
<h1 class="display-1">商品管理</h1>
<table class="table table-striped">
<thead class="table-primary">
<tr>
<th>ID</th>
<th>メーカー</th>
<th>商品名</th>
<th>価格</th>
</tr>
</thead>
<tbody>
{% for a in data %}
<tr>
<td>{{ a.id }}</td>
<td>{{ a.maker_id }}</td>
<td>{{ a.item_name }}</td>
<td>{{ a.price }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</body>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>
</html>
projectをデプロイします
space push
これでデプロイ終了です。実行するにはcanvasに作成されたアイコンを選択してください。
これで動くは動きますが、メーカーの部分にメーカーIDが出てます。そうです、phpの時はMariaDBを使っていましたから、RDBだったわけで、リレーションDB用のテーブル設計になっています。
NoSQLでは、リレーションができませんので、このままでは不便です。対策としては、リレーションを使わずに直接メーカー名を入れて置く。またはそのたびにIDからメーカー名を取得して書き換える。あるいは、最初にテーブルを読み込んでおいて書き換える、などです。
今回は、メーカーが少ないので辞書型に読み込んで、書き換えるサンプルを作っておきますが、これが正しいとは思えません。
main.py
from flask import Flask, render_template
from deta import Deta
app = Flask(__name__)
#リスト作成
# myitems = [{"id":1,"maker_id":1, "item_name":"いちご","price":180}]
# makers = [{"id":1,"name":"山田さん","address":"鹿児島市中央町","tel":"099-123-4567"}]
#データベース読込
deta = Deta("data key")
myitems = deta.Base("my_items")
#メーカーデータを展開する
makers = deta.Base("makers")
makerdata = makers.fetch(query=None)
allmakers = makerdata.items
mk = { m['id']:m['name'] for m in allmakers}
@app.route('/')
def index():
itemsdata = myitems.fetch(query=None)
allitems = itemsdata.items
allitems = sorted(allitems,key=lambda x: x['id'])
for data in allitems:
for key,value in data.items():
if key=="maker_id":
data[key] = mk[value] #メーカーIDと名前をすり替える
return render_template('index.html', data = allitems)
なんとか動きました
relation_myitemsで実験できます
まだ正解がわかりません。もっとましな答えを探してみます