読者です 読者をやめる 読者になる 読者になる

謎言語使いの徒然

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

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

Django Python 日記

コレまでの履歴

  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)