モデルとして定義した Python 型のデータをデータベースに登録したい

1,350 views
Skip to first unread message

Hajime Fujita

unread,
Aug 21, 2010, 10:59:05 AM8/21/10
to django-ja
藤田です。

たびたび質問を失礼いたします。
相変わらず RSS リーダー作成のために Django と格闘していますが…

以下のようにモデルを作成してデータベースに登録したいと考えています。

class Site( models.Model ):
user = models.ManyToManyField( Reader )
site_name = models.CharField( max_length = 1024 )
rss_link = models.URLField( blank = False, max_length = 1024 )
last_update = models.DateTimeField()
entry = []

ここで、Django のフィールド型として定義されている変数、
user, site_name, rss_link, last_update はオブジェクトの save() により
データベースへ登録できるのですが、

Python 型(リスト)である entry は save() 後に get しても
変更が反映されておらず、常に空 [] のままです。
プリミティブな型は登録されないなどの制約があるのでしょうか?

# 「常に」というと少し語弊があるのですが…より正確には、少なくとも
# Web サーバを再起動等したりした後に、get すると空に戻っています。

ご教示くださいますよう、どうぞよろしくお願い致します。

tokibito

unread,
Aug 21, 2010, 11:43:53 AM8/21/10
to django-ja
岡野です。

Djangoのモデルフィールドはデータベースと対応していますが、そうでないものに関しては自動で登録されるようなことはありません。
おっしゃられているentryをデータベースに保存する場合は、EntryのDjangoのモデルを作成し、
ForeignKeyやManyToManyFieldを利用してモデル間の関係性を持たせることで、簡単にデータベースに登録することができます。

ドキュメントのリレーションについての項が参考になると思います。
http://djangoproject.jp/doc/ja/1.0/topics/db/models.html#id11

Hajime Fujita

unread,
Aug 22, 2010, 4:13:53 AM8/22/10
to django-ja
藤田です。

ご回答ありがとうございます。

やはり、プリミティブな型をデータベースに登録することは難しく、
各 Entry をモデルとして定義して登録する方法が素直なのですね。
よく分かりました。

ただ、そういうデータ構造にしてしまうと、データが多重化するように思いますが…。
つまり、複数のユーザによる利用を考えると、各ユーザが同一のサイトを登録することにより、
同じデータがデータベースに複数存在することになり、利用効率が悪くなるように思います。

一方で、既読・未読の管理などは各ユーザ間で異なるデータを保持する必要があるので、
これをうまく処理する方法はないものかと考えて、モデルの中にリストを持っておけば
良いと考えたのですが…。

ともかく、データの多重化やデータベースへのアクセス頻度などの問題を無視して、
まずは素直なデータ構造で実装してみたいと思います。

ありがとうございました。

kidd alex

unread,
Aug 31, 2010, 3:11:34 PM8/31/10
to djan...@googlegroups.com
遅レスで申し訳ありません。はじめまして、salexkiddと申します。

さて、Djangoのモデルにて配列をカラムに収めたいとのことですが、
これは岡野様の言われるように、ForeignKeyやManyToManyFieldを利用するのも1つの手なのですが、
モデルクラス上に1つのCharField型のフィールドを用意し、そこにPythonの標準モジュールである
pickleとbase64を用いることで、配列や辞書型など、様々なデータをそのまま収めることができます。

以下にテストコードを記載します。("manage.py shell" 等で動かしてみてください)
>>> import pickle, base64
>>> array = [1,2,3,4,5]
>>> dump_data = pickle.dumps(array)
>>> b64_data = base64.b64encode(dump_data)

データを戻したい場合は以下のようにします。
>>> pickle_data = base64.b64decode(b64_data)
>>> pickle.loads(pickle_data)

これにより、収めたいデータ"array"はPickleで永続化され、その後b64encodeによって文字列化されます。
この pickle & b64encode されたデータをView関数中でCharField型のフィールドに収めることによって配列や辞書型、その他のデータ型を格納することができます。

ただし、CharFieldのlengthには気をつける必要があります。(MySQLやSQLite等のDBにより、Lengthの最大値などが違います)
また、データをUpdateする際のView中のフォームの生成にも気を配る必要があります。

面倒な方法ですが、ちょっとした面白さは保証します ;)

2010年8月22日17:13 Hajime Fujita <hajime...@gmail.com>:
--
-----------------                       http://djangoproject.jp/                         -----------------
You received this message because you are subscribed to the Google Groups "django-ja" group.
To post to this group, send email to djan...@googlegroups.com
To unsubscribe from this group, send email to django-ja-...@googlegroups.com
For more options, visit this group at http://groups.google.com/group/django-ja

Hajime Fujita

unread,
Sep 2, 2010, 8:14:24 AM9/2/10
to django-ja
藤田です。

なるほどー!
かなりテクニカルな方法で、確かに実装に骨が折れそうですが、
これならデータベースを効率よく使えそうです。

ちょっと試してみます。
ありがとうございました!


On 9月1日, 午前4:11, kidd alex <salexk...@gmail.com> wrote:
> 遅レスで申し訳ありません。はじめまして、salexkiddと申します。
>
> さて、Djangoのモデルにて配列をカラムに収めたいとのことですが、
> これは岡野様の言われるように、**ForeignKeyやManyToManyFieldを利用するのも1つの手なのですが、
> モデルクラス上に1つのCharField型のフィールドを用意し、そこにPythonの標準モジュールである
> pickleとbase64を用いることで、配列や辞書型など、様々なデータをそのまま収めることができます。
>
> 以下にテストコードを記載します。("manage.py shell" 等で動かしてみてください)
>
> >>> import pickle, base64
> >>> array = [1,2,3,4,5]
> >>> dump_data = pickle.dumps(array)
> >>> b64_data = base64.b64encode(dump_data)
>
> データを戻したい場合は以下のようにします。
>
> >>> pickle_data = base64.b64decode(b64_data)
> >>> pickle.loads(pickle_data)
>
> これにより、収めたいデータ"array"はPickleで永続化され、その後b64encodeによって文字列化されます。
> この pickle & b64encode
> されたデータをView関数中でCharField型のフィールドに収めることによって配列や辞書型、その他のデータ型を格納することができます。
>
> ただし、CharFieldのlengthには気をつける必要があります。(MySQLやSQLite等のDBにより、Lengthの最大値などが違います)
> また、データをUpdateする際のView中のフォームの生成にも気を配る必要があります。
>
> 面倒な方法ですが、ちょっとした面白さは保証します ;)
>
> 2010年8月22日17:13 Hajime Fujita <hajime.fuj...@gmail.com>:

Iqbal Abdullah

unread,
Sep 19, 2010, 11:51:14 PM9/19/10
to djan...@googlegroups.com
イクバルです。

今このスレッドをみてふっと思ったんですが、pickleからの文字列をbase64にまたかける必要があるでしょうか。

data = pickle.dumps(array)

dataって、すでに文字配列ですからそのままCharFieldとして保存することもできるはずなんで、取り出すときも

array = pickle.loads(data)

になるんではないかと思いますが、base64にする必要があるでしょうか。

2010/9/1 kidd alex <sale...@gmail.com>:

kidd alex

unread,
Sep 20, 2010, 9:52:59 AM9/20/10
to djan...@googlegroups.com
イクバルさん

どうも、salexkiddです。

昨今はやっと涼しくなり、これからどんどんHackが進む季節になり、嬉しい限りです。

さて、返信を頂いた件ですが、

もし、Pickle化したデータをAdminサイト等で表示/保存しないのならばそれで問題ありません。
が、もしAdminサイトでデータを表示する場合には少々問題が起きます。
例えば、

>>>pickle.dumps('abcdefg')

とすると、

"S'abcdefg'\np0\n."

というデータが返ります。これを、何らかのModelのオブジェクトのデータとして保存したとします

>>> t = test_model()
>>> t.p = pickle.dumps('abcdefg')

このモデルをAdminサイトで確認するとすると、テキストフィールドに

S'abcdefg' p0 .

と、\n部分が表示されず、このまま保存するとPickle化したデータが壊れてしまいます。
(また、AdminFormを適切にTextAreaにしても、そのままでは保存時に改行が\r\nに変化してしまいます)

ようは、こんな面倒な事のために悩むのならばもういっそBase64化してしまえばOK! ということです。

(また、Base64化すればDBを直接みても変な改行が入らなくて精神的です  ;)  )

では失礼いたします。

2010年9月20日12:51 Iqbal Abdullah <iq...@marimore.co.jp>:
Reply all
Reply to author
Forward
0 new messages