謎言語使いの徒然

適当に気になった技術や言語を流すブログ。

【モデル作成】Django 初心者がコミュニティサイト的な何かにチャレンジしてみる

コレまでの履歴

  1. 【インストール編】Django 初心者がコミュニティサイト的な何かにチャレンジしてみる
  2. 【プロジェクト作成】Django 初心者がコミュニティサイト的な何かにチャレンジしてみる

三回目、データベースモデルを作ってみる。
その前に、先ず使いやすいテキストエディタ探しておこう。
知り合い内とかで聞く名前はこんな感じだった。IDE が混じってるけど気にしてはいけない。

何故ここで勧めるかって?あったほうが楽できるから。
因みにこのBlogでスクリーンショット取るときはKomodoEditなのであしからず。

先ずは、アプリケーションを宣言する

先ずはアプリケーションを宣言してみる。
土台だけではどうし様もないしね、、、。
ということで、コンソールでアプリケーションを宣言してみる。
コマンドはこんな感じ

manage.py startapp community

コミュニティという名前のアプリケーションを開始すると。
間違えてしまった場合は、作成されたディレクトリ以下を削除すればOK!
community ディレクトリの中身は以下の通り。

  • __init__.py 初期化ファイル(特に使わない)
  • models.py モデルファイル(ここに DB 定義とか書いておく)
  • tests.py テストコード(ユニットテスト用にしか見えない)
  • views.py ビューコード(Django の View はコントローラ的な、、、)

tests.py はインストールのとき、「django-command-extensions」を入れた影響かな?(デフォルトだと無かった気がする)

モデルを作ってみる

で、モデルを作成してみる。
Symfony(PHP)なら、yml 編集してコンソールコマンド。RubyOnRails(Ruby)ならコンソールでコマンド一発。
Django の場合は、モデルを書く。(RubyOnRails では、モデルクラスと、DB適用用のマイグレートクラスの二つがあるが、Django はモデルだけ書けばそれをマイグレートクラスとしても適用できる。そういう意味では分かりやすくてよいと思った。)

models.py がそれに当たる。
先ず、デフォであるものは何かと考えてみると、前回の admin 見ればいい。

  • 権限
  • メールアドレス

これは元々ある、、、ということで、コミュニティサイトで他に足りないものを考える。

  • フレンド登録
  • ニックネーム
  • ホームページ
  • 趣味
  • 特技
  • 都道府県

挙げるとキリがないか、、、、ともすれば、必須っぽいもの意外は、後から質問追加できる形がいいのかなー。
保存するのはRDBだから勝手に拡張とかやりにくいコト考えて、切り離せるものは切り離す。
「フレンド登録」はユーザ間を繋げるデータなので、ユーザ情報にくっつけれないみたいな考え方しとく。
まぁ独断と偏見でこんなものを指定しとく。

  • ニックネーム
  • ホームページ

ホームページは何か違うんじゃね?と思う人もいると思うけど、俺が欲しいw
ということでこんなモデルを作ってみる。

# coding:utf-8
from django.db import models
from django.contrib import admin
from django.contrib.auth.models import User

class UserProfile(models.Model):
    nick_name = models.TextField(unique=True,max_length=64)
    home_page = models.URLField(verify_exists=False,null=True,blank=True)

admin.site.register(UserProfile) # admin 管理サイトに登録

して、どうやってユーザテーブルと紐付けしようかと悩んだら、コレ。
http://djangoproject.jp/doc/ja/1.0/topics/auth.html?highlight=auth#storing-additional-information-about-users
公式ドキュメントがしっかりしてるのはいいことね。
ということで以下のように変更。

# coding:utf-8
from django.db import models
from django.contrib import admin
from django.contrib.auth.models import User

class UserProfile(models.Model):
    target_user = models.ForeignKey(User,unique=True)
    nick_name = models.TextField(unique=True,max_length=64)
    home_page = models.URLField(verify_exists=False,null=True,blank=True)

admin.site.register(UserProfile)

そして、多分 settings.py あたりだろうか?
AUTH_PROFILE_MODULE をセットする。ついでに、アプリケーションの登録もしておこう。

AUTH_PROFILE_MODULE = 'community.userprofile'
INSTALLED_APPS = (
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.sites',
    'django.contrib.admin',
    'community',
)

他に、必要なので特殊なのはフレンドリンクだろうか?
ForeignKey の使い方はさっきのを参照してやってみる。

# coding:utf-8
from django.db import models
from django.contrib import admin
from django.contrib.auth.models import User

class UserProfile(models.Model):
    target_user = models.ForeignKey(User,unique=True)
    nick_name = models.TextField(unique=True,max_length=64)
    home_page = models.URLField(verify_exists=False,null=True,blank=True)

class UserLink(models.Model):
    target1 = models.ForeignKey(User,unique=False)
    target2 = models.ForeignKey(User,unique=False)

admin.site.register(UserProfile)
admin.site.register(UserLink)

この辺で不安なので「manage.py syncdb」をかけてみる(この操作でDBに適用する)。
すると、二つほどエラーが出た。

Error: One or more models did not validate:
community.userlink: Accessor for field 'target1' clashes with related field 'Use
r.userlink_set'. Add a related_name argument to the definition for 'target1'.
community.userlink: Accessor for field 'target2' clashes with related field 'Use
r.userlink_set'. Add a related_name argument to the definition for 'target2'.

関係がクラッシュするから related_name を設定しなさいとのこと。

# coding:utf-8
from django.db import models
from django.contrib import admin
from django.contrib.auth.models import User

class UserProfile(models.Model):
    target_user = models.ForeignKey(User,unique=True)
    nick_name = models.TextField(unique=True,max_length=64)
    home_page = models.URLField(verify_exists=False,null=True,blank=True)

class UserLink(models.Model):
    target1 = models.ForeignKey(User,unique=False,related_name='target1')
    target2 = models.ForeignKey(User,unique=False,related_name='target2')

admin.site.register(UserProfile)
admin.site.register(UserLink)

これで問題なく通った。
最後に、SNS 的な質問と、その結果の記録フィールドでも用意してみようと思った。
以下の感じ

  • ProfileSubset : 質問と、質問の序列、入力タイプ
  • ProfileSubsetValues : ProfileSubset が選択型だった場合の選択肢
  • UserProfileSubset : ユーザと質問(およびその解答)の紐付け

結果コードはこんな感じ?

# coding:utf-8
from django.db import models
from django.contrib import admin
from django.contrib.auth.models import User

class UserProfile(models.Model):
    target_user = models.ForeignKey(User,unique=True)
    nick_name = models.TextField(unique=True,max_length=64)
    home_page = models.URLField(verify_exists=False,null=True,blank=True)
    def __unicode__(self):
        return self.nick_name

class UserLink(models.Model):
    target1 = models.ForeignKey(User,unique=False,related_name='target1')
    target2 = models.ForeignKey(User,unique=False,related_name='target2')
    def __unicode__(self):
        return self.target1.name + ' to ' + self.target2.name

# Question and question type
class ProfileSubset(models.Model):
    # Profile view name
    name = models.TextField(unique=True,null=False,max_length=32)
    # profile data type(text:0 , radio:1 , chexkbox:2 , intval:3)
    type = models.IntegerField(null=False)
    # Question Rank
    rank = models.IntegerField(null=False)
    def __unicode__(self):
        return self.name

# UserProfile Type extend values
# raido , checkbox
class ProfileSubsetValues(models.Model):
    # Profile subset
    parent = models.ForeignKey(ProfileSubset)
    # subset value
    value = models.TextField(max_length=32)
    def __unicode__(self):
        return self.parent.name + " : " + self.value

# User inform
class UserProfileSubset(models.Model):
    # taeget user
    user = models.ForeignKey(User)
    # target subset
    subset = models.ForeignKey(ProfileSubset)
    # subset value
    value = models.TextField(max_length=255)
    def __unicode__(self):
        return str(self.user) + " : " + self.subset.name + "=" + self.value

admin.site.register(UserProfile)
admin.site.register(UserLink)
admin.site.register(ProfileSubset)
admin.site.register(ProfileSubsetValues)
admin.site.register(UserProfileSubset)