GAEで多対多のモデル作りに苦しむ
現在作成中のmrsにおいて、エントリーに対してtagを付与する必要がある。これが、GoogleAppEngineのDatastore APIでどのように書けばいいのか四苦八苦している。“多対多ムズイ”とTwitterにかいたところ、id:Voluntas氏より
GAE は RDB ではないと認識した方がいい、RDB 忘れて書いた方がいいよ。
とのアドバイスを頂いたのですが、そもそもRDBってなによ?という状況なので、1から考え直す事にする。アドバイスありがとうございます>Vol氏
1対他の場合
これは凄く簡単というか、シンプルにFK的なものが有って
class Author(db.Model): name = db.StringProperty() class Story(db.Model): author = db.ReferenceProperty(Author) story = db.get(story_key) author_name = story.author.name (via:http://code.google.com/appengine/docs/datastore/typesandpropertyclasses.html#ReferenceProperty)
と書けば良い。多対多には、参考にならなさそうなので深追いはやめておく。
多対他への考察
中間マップ作成
- coreデータ
- c_id
- body
- tagデータ
- t_id
- body
上記テーブル(クラス)を結びつける為に
- tableデータ
- core_id
- tag_id
このような中間テーブルを作成し、関連を作成する。
問題点は、コア1個、タグ3個の入力に対して、テーブルが3個作成されるので、倍近いデータが作成されることになる。この問題も、ある程度のタグが作成されてしまえば、タグは使い回しの状態に入るので倍にはならない。しかし、コアとは別にタグの数だけテーブルが作成されるので、この状態では、倍以上のデータが作成されることになる。
悩ましいな。
ListPropertyを使用する
これが、本命な気がする。Datastore APIのプロパティーにListを持てる奴が有るのでこれを利用してどうにか出来ないか考えてみた。ここでめんどくさいのはListの中身に任意のClassを持てない事(持てるかも知れないが・・・) コレさえ出来れば、良いのになぁと思うが出来ないものは出来ない。Listに入ることができる、ValueTypeは、
- str or unicode
- bool
- int or long
- float
- datetime.datetime
- db.Key By path elements (kind, ID or name, kind, ID or name...)
- UserProperty users.User By email address (Unicode)
- BlobProperty db.Blob (not orderable)
- TextProperty db.Text (not orderable)
- CategoryProperty db.Category Unicode
- LinkProperty db.Link Unicode
- EmailProperty db.Email Unicode
- GeoPtProperty db.GeoPt By latitude, then longitude
- IMProperty db.IM Unicode
- PhoneNumberProperty db.PhoneNumber Unicode
- PostalAddressProperty db.PostalAddress Unicode
- RatingProperty db.Rating
だけらしい。この中で使うならばdb.Keyが適切かと思われる。
ただいまのモデルは以下の通り
#!/usr/bin/env python # encoding: utf-8 """ model.py Created by atusi on 2008-04-13. Copyright (c) 2008 a2c.biz . All rights reserved. """ from google.appengine.api import users from google.appengine.ext import db class UserPrefs(db.Model): created_at = db.DateTimeProperty(auto_now_add = True) user = db.UserProperty(required = True) description = db.StringProperty() class Tag(db.Model): created_at = db.DateTimeProperty( auto_now_add = True ) body = db.StringProperty( required = True ) class Type(db.Model): body = db.StringProperty( required = True ) description = db.StringProperty() class Core(db.Model): created_at = db.DateTimeProperty( auto_now_add=True ) usr = db.ReferenceProperty(UserPrefs) body = db.StringProperty(required = True) #types = db.CategoryProperty(Type) tags = db.ListProperty(db.Key)
これで、コアデータに対してどのタグが使われているのかが2つのテーブルのみで作成可能となった。