「Django 最初のアプリケーション 1」の版間の差分
ナビゲーションに移動
検索に移動
1行目: | 1行目: | ||
− | ==Django 最初のアプリケーション 1 (環境設定~モデルの作成)== | + | ==[[Django 最初のアプリケーション 1]] (環境設定~モデルの作成)== |
− | + | [Django][Python][[Django 最初のアプリケーション 2]|[次]] | |
− | + | [[Python]]の概要も分かり易い. | |
{{amazon|477413760X}} | {{amazon|477413760X}} | ||
10行目: | 10行目: | ||
を参考にサンプルアプリケーションを作成してみる | を参考にサンプルアプリケーションを作成してみる | ||
− | === | + | ===[[Django]]がインストールされている=== |
− | *Django インストール | + | *[[Django インストール]] |
=====import django がpythonインタプリタから行えること===== | =====import django がpythonインタプリタから行えること===== | ||
# python | # python | ||
− | Python 2.6.2 (r262:71600, Jun 13 2009, 02:28:29) | + | [[Python]] 2.6.2 (r262:71600, Jun 13 2009, 02:28:29) |
[GCC 4.1.2 20070626 (Red Hat 4.1.2-13)] on linux2 | [GCC 4.1.2 20070626 (Red Hat 4.1.2-13)] on linux2 | ||
Type "help", "copyright", "credits" or "license" for more information. | Type "help", "copyright", "credits" or "license" for more information. | ||
>>> import django | >>> import django | ||
− | ===== | + | =====[[Help]]を確認===== |
>>> help(django) | >>> help(django) | ||
− | Help on package django: | + | [[Help]] on package django: |
NAME | NAME | ||
35行目: | 35行目: | ||
===プロジェクトの作成=== | ===プロジェクトの作成=== | ||
====django-admin.py コマンドの実行==== | ====django-admin.py コマンドの実行==== | ||
− | * | + | *[[Django]]を最初に利用する場合、初期化処理を行う必要がある |
*コードを置こうと思っているディレクトリで、以下のコマンドを実行(mysiteディレクトリが作成される) | *コードを置こうと思っているディレクトリで、以下のコマンドを実行(mysiteディレクトリが作成される) | ||
# django-admin.py startproject mysite | # django-admin.py startproject mysite | ||
41行目: | 41行目: | ||
* | * | ||
<blockquote>プロジェクト名に、djangoやtestは避けること</blockquote> | <blockquote>プロジェクト名に、djangoやtestは避けること</blockquote> | ||
− | *django-admin.py | + | *django-admin.py は、[[Django]] を setpu.py でインストールしたシステムパス(/usr/local/binのような)にある。 |
# whereis django-admin.py | # whereis django-admin.py | ||
django-admin: /usr/local/bin/django-admin.py | django-admin: /usr/local/bin/django-admin.py | ||
59行目: | 59行目: | ||
|- | |- | ||
|__init__.py | |__init__.py | ||
− | | | + | |このディレクトリがパッケージだと[[Python]]に伝える空のファイル |
|- | |- | ||
|manage.py | |manage.py | ||
68行目: | 68行目: | ||
|- | |- | ||
|urls.py | |urls.py | ||
− | | | + | |プロジェクトのU[[R]]L宣言 |
|- | |- | ||
|} | |} | ||
78行目: | 78行目: | ||
0 errors found | 0 errors found | ||
− | Django version 1.0.2 final, using settings 'mysite.settings' | + | [[Django]] version 1.0.2 final, using settings 'mysite.settings' |
Development server is running at http://127.0.0.1:8000/ | Development server is running at http://127.0.0.1:8000/ | ||
− | Quit the server with | + | Quit the server with CONT[[R]]OL-C. |
− | * | + | *開発サーバーを起動すると、[[Python]]で書かれた軽量サーバーが http://127.0.0.1:8000/ で起動する |
====起動ポート、IPアドレスを変更する==== | ====起動ポート、IPアドレスを変更する==== | ||
*デフォルトで開発サーバーはポート8000で起動するが、ポートを指定して起動することもできる。 | *デフォルトで開発サーバーはポート8000で起動するが、ポートを指定して起動することもできる。 | ||
90行目: | 90行目: | ||
0 errors found | 0 errors found | ||
− | Django version 1.0.2 final, using settings 'mysite.settings' | + | [[Django]] version 1.0.2 final, using settings 'mysite.settings' |
Development server is running at http://192.168.24.14:8080/ | Development server is running at http://192.168.24.14:8080/ | ||
− | Quit the server with | + | Quit the server with CONT[[R]]OL-C. |
=====起動===== | =====起動===== | ||
[[File:0350_django_firstapp01.jpg]] | [[File:0350_django_firstapp01.jpg]] | ||
103行目: | 103行目: | ||
|- | |- | ||
|DATABASE_ENGINE | |DATABASE_ENGINE | ||
− | |'postgresql_psycopg2'、'mysql'、' | + | |'postgresql_psycopg2'、'mysql'、'[[sqlite]]3'その他 |
|- | |- | ||
|DATABASE_NAME | |DATABASE_NAME | ||
− | | | + | |データベース名。[[SQL]]iteの場合、絶対パス名存在しない場合、初回自動的に作成される。 |
|- | |- | ||
|DATABASE_USER | |DATABASE_USER | ||
− | | | + | | データベースユーザー名。[[SQL]]iteの場合不要 |
|- | |- | ||
|DATABASE_PASSWORD | |DATABASE_PASSWORD | ||
− | | | + | |データベースパスワード。[[SQL]]iteの場合不要 |
|- | |- | ||
|DATABASE_HOST | |DATABASE_HOST | ||
− | | | + | |データーベースのホスト。設定しない場合、物理的に同じマシンとみなされる。[[SQL]]iteでは不要 |
|- | |- | ||
|} | |} | ||
− | ==== | + | ====[[SQL]]iteは、Pytho2.5以降に含まれる==== |
− | *SQLiteを使用する場合、DATABASE_ENGINEに | + | *SQLiteを使用する場合、DATABASE_ENGINEに [[sqlite]]3を指定する |
− | * | + | *[[Python]]2.5以降に含まれるため、他にインストール等不要 |
− | <blockquote> | + | <blockquote>[[SQL]]iteを指定した場合準備は不要。データベースファイルは必要になったときに作成される</blockquote> |
− | ==== | + | ====[[PostgreSQL]]を利用してみる==== |
− | *PostgreSQL 8.3.5 インストール | + | *[[PostgreSQL 8.3.5 インストール]] |
− | *PostgresSQL 8.3.5 起動と停止 | + | *[[PostgresSQL 8.3.5 起動と停止]] |
− | *PostgreSQL pgAdminのインストール | + | *[[PostgreSQL pgAdminのインストール]] |
DATABASE_ENGINE = 'postgresql_psycopg2' | DATABASE_ENGINE = 'postgresql_psycopg2' | ||
DATABASE_NAME = 'testdb' | DATABASE_NAME = 'testdb' | ||
− | + | DATABASE_USE[[R]] = 'postgres' | |
− | + | DATABASE_PASSWO[[R]]D = '******' | |
DATABASE_HOST = '' | DATABASE_HOST = '' | ||
− | + | DATABASE_PO[[R]]T = '5432' | |
− | ====psycopg Python-PostgreSQL Database Adapterのインストール==== | + | ====psycopg Python-[[PostgreSQL]] Database Adapterのインストール==== |
http://www.initd.org/pub/software/psycopg/ | http://www.initd.org/pub/software/psycopg/ | ||
http://www.initd.org/pub/software/psycopg/psycopg2-2.0.11.tar.gz | http://www.initd.org/pub/software/psycopg/psycopg2-2.0.11.tar.gz | ||
158行目: | 158行目: | ||
File "<stdin>", line 1, in <module> | File "<stdin>", line 1, in <module> | ||
File "/usr/local/lib/python2.6/site-packages/psycopg2/__init__.py", line 60, in <module> | File "/usr/local/lib/python2.6/site-packages/psycopg2/__init__.py", line 60, in <module> | ||
− | from _psycopg import | + | from _psycopg import BINA[[R]]Y, NUMBE[[R]], ST[[R]]ING, DATETIME, [[R]]OWID |
ImportError: libpq.so.5: cannot open shared object file: No such file or directory | ImportError: libpq.so.5: cannot open shared object file: No such file or directory | ||
− | *[PostgreSQL 8.3.5 インストール | + | *[[PostgreSQL 8.3.5 インストール|libpq.so が見つからないエラー]] |
− | # | + | # LD_LIB[[R]]A[[R]]Y_PATH=/usr/local/pgsql/lib:$LD_LIB[[R]]A[[R]]Y_PATH |
OK | OK | ||
167行目: | 167行目: | ||
====syncdbの実行==== | ====syncdbの実行==== | ||
− | ===== | + | =====[[PostgreSQL]]を起動しておく===== |
#pg_ctl start | #pg_ctl start | ||
=====syncdbコマンドの実行===== | =====syncdbコマンドの実行===== | ||
179行目: | 179行目: | ||
Creating table django_site | Creating table django_site | ||
− | You just installed Django's auth system, which means you don't have any superusers defined. | + | You just installed [[Django]]'s auth system, which means you don't have any superusers defined. |
Would you like to create one now? (yes/no): yes | Would you like to create one now? (yes/no): yes | ||
Username (Leave blank to use 'root'): | Username (Leave blank to use 'root'): | ||
192行目: | 192行目: | ||
[[File:0351_django_firstapp02.jpg]] | [[File:0351_django_firstapp02.jpg]] | ||
=====INSTALLED_APPS設定===== | =====INSTALLED_APPS設定===== | ||
− | * | + | *INSTALLED_APPS変数は、この[[Django]]インスタンスからアクティベートされるすべての[[Django]]アプリケーションで保持される |
INSTALLED_APPS = ( | INSTALLED_APPS = ( | ||
'django.contrib.auth', | 'django.contrib.auth', | ||
203行目: | 203行目: | ||
====アプリケーションの作成==== | ====アプリケーションの作成==== | ||
*ここまでで、プロジェクト環境は作成された | *ここまでで、プロジェクト環境は作成された | ||
− | * | + | *Djangoのアプリケーションは、[[Python]]のパッケージ |
<blockquote>プロジェクトは設定のコレクションであり、アプリケーションは特定のWebサイト。プロジェクトは複数のアプリケーションを含み、アプリケーションは複数のプロジェクトに属すことができる</blockquote> | <blockquote>プロジェクトは設定のコレクションであり、アプリケーションは特定のWebサイト。プロジェクトは複数のアプリケーションを含み、アプリケーションは複数のプロジェクトに属すことができる</blockquote> | ||
213行目: | 213行目: | ||
|-- __init__.py | |-- __init__.py | ||
|-- models.py | |-- models.py | ||
− | `-- | + | `-- [[vi]]ews.py |
====モデルの作成==== | ====モデルの作成==== | ||
− | *Django Web アプリケーションでは、モデルを定義する | + | *[[Django]] Web アプリケーションでは、モデルを定義する |
*単純なサンプルアプリケーション(poll)では、2つのモデル polls、choicesを作成する | *単純なサンプルアプリケーション(poll)では、2つのモデル polls、choicesを作成する | ||
*pollは、質問と発表日、choiceは選択テキストと同意への投票の2つのフィールドを持つ | *pollは、質問と発表日、choiceは選択テキストと同意への投票の2つのフィールドを持つ | ||
244行目: | 244行目: | ||
====DDLの確認~テーブルの生成==== | ====DDLの確認~テーブルの生成==== | ||
− | * | + | *[[Django]]は、pollsを含むmysiteを認識しているので、以下のコマンドを実行 |
− | *[PostgresSQL 8.3.5 起動と停止] | + | *[[PostgresSQL 8.3.5 起動と停止|データベースを起動しておく]] |
=====DDLを発行し、テープルを作成する===== | =====DDLを発行し、テープルを作成する===== | ||
# python manage.py sql polls | # python manage.py sql polls | ||
BEGIN; | BEGIN; | ||
− | + | C[[R]]EATE TABLE "polls_poll" ( | |
− | "id" serial NOT NULL | + | "id" serial NOT NULL P[[R]]IMA[[R]]Y KEY, |
"question" varchar(200) NOT NULL, | "question" varchar(200) NOT NULL, | ||
"pub_date" date NOT NULL | "pub_date" date NOT NULL | ||
) | ) | ||
; | ; | ||
− | + | C[[R]]EATE TABLE "polls_choice" ( | |
− | "id" serial NOT NULL | + | "id" serial NOT NULL P[[R]]IMA[[R]]Y KEY, |
− | "poll_id" integer NOT NULL | + | "poll_id" integer NOT NULL [[R]]EFE[[R]]ENCES "polls_poll" ("id") DEFE[[R]][[R]]ABLE INITIALLY DEFE[[R]][[R]]ED, |
"choice" varchar(200) NOT NULL, | "choice" varchar(200) NOT NULL, | ||
"votes" integer NOT NULL | "votes" integer NOT NULL | ||
) | ) | ||
; | ; | ||
− | + | [[COM]]MIT; | |
=====テーブルの生成===== | =====テーブルの生成===== | ||
# python manage.py syncdb | # python manage.py syncdb | ||
287行目: | 287行目: | ||
>>> p.id | >>> p.id | ||
1L | 1L | ||
− | # | + | #[[Python]]の属性を経由してデータベースのカラムにアクセス |
>>> p.question | >>> p.question | ||
"What's up?" | "What's up?" | ||
328行目: | 328行目: | ||
>>> from mysite.polls.models import Poll,Choice | >>> from mysite.polls.models import Poll,Choice | ||
− | # | + | #[[Django]]は高機能なlookup APIを提供 |
>>> Poll.objects.filter(id=1) | >>> Poll.objects.filter(id=1) | ||
[<Poll: What's up?>] | [<Poll: What's up?>] | ||
339行目: | 339行目: | ||
True | True | ||
− | # | + | #INSE[[R]]Tステートメントの記述なしに、createの呼び出しでChoiceオブジェクトを生成する |
#外部キー制約を指定したのでchoice_set が有効 | #外部キー制約を指定したのでchoice_set が有効 | ||
>>> p.choice_set.create(choice='Not much',votes=0) | >>> p.choice_set.create(choice='Not much',votes=0) | ||
353行目: | 353行目: | ||
<blockquote>APIは自動的にリレーションシップ(参照整合性制約)をフォローする。アンダースコアの2重続きは、リレーションシップを区別する</blockquote> | <blockquote>APIは自動的にリレーションシップ(参照整合性制約)をフォローする。アンダースコアの2重続きは、リレーションシップを区別する</blockquote> | ||
− | [[Django 最初のアプリケーション 2 | + | [[Django 最初のアプリケーション 2]|[次]] |
2020年2月16日 (日) 04:24時点における最新版
目次
Django 最初のアプリケーション 1 (環境設定~モデルの作成)
[Django][Python][[Django 最初のアプリケーション 2]|[次]]
Pythonの概要も分かり易い.
を参考にサンプルアプリケーションを作成してみる
Djangoがインストールされている
import django がpythonインタプリタから行えること
# python Python 2.6.2 (r262:71600, Jun 13 2009, 02:28:29) [GCC 4.1.2 20070626 (Red Hat 4.1.2-13)] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> import django
Helpを確認
>>> help(django) Help on package django: NAME django FILE /usr/local/lib/python2.6/site-packages/django/__init__.py PACKAGE CONTENTS bin (package) conf (package) contrib (package) :
プロジェクトの作成
django-admin.py コマンドの実行
- Djangoを最初に利用する場合、初期化処理を行う必要がある
- コードを置こうと思っているディレクトリで、以下のコマンドを実行(mysiteディレクトリが作成される)
# django-admin.py startproject mysite
<blockquote>プロジェクト名に、djangoやtestは避けること</blockquote>
- django-admin.py は、Django を setpu.py でインストールしたシステムパス(/usr/local/binのような)にある。
# whereis django-admin.py django-admin: /usr/local/bin/django-admin.py
作成されるファイル
- startprojectは以下のファイルを作成
# tree . `-- mysite |-- __init__.py |-- manage.py |-- settings.py `-- urls.py
ファイル | 概要 |
---|---|
__init__.py | このディレクトリがパッケージだとPythonに伝える空のファイル |
manage.py | プロジェクトと対話するためのコマンドラインユーティリティ |
settings.py | プロジェクトの設定ファイル |
urls.py | プロジェクトのURL宣言 |
開発サーバー
- mysiteディレクトリへ入って、以下を実行
# python manage.py runserver Validating models... 0 errors found Django version 1.0.2 final, using settings 'mysite.settings' Development server is running at http://127.0.0.1:8000/ Quit the server with CONTROL-C.
- 開発サーバーを起動すると、Pythonで書かれた軽量サーバーが http://127.0.0.1:8000/ で起動する
起動ポート、IPアドレスを変更する
- デフォルトで開発サーバーはポート8000で起動するが、ポートを指定して起動することもできる。
# python manage.py runserver 8080
- IPアドレスはローカルホストしかリッスンしていないようだが、指定することができる
# python manage.py runserver 192.168.24.14:8080 Validating models... 0 errors found Django version 1.0.2 final, using settings 'mysite.settings' Development server is running at http://192.168.24.14:8080/ Quit the server with CONTROL-C.
起動
データベースの設定
- データベースの接続設定に応じて、setting.pyを編集する。
設定項目 | 内容 |
---|---|
DATABASE_ENGINE | 'postgresql_psycopg2'、'mysql'、'sqlite3'その他 |
DATABASE_NAME | データベース名。SQLiteの場合、絶対パス名存在しない場合、初回自動的に作成される。 |
DATABASE_USER | データベースユーザー名。SQLiteの場合不要 |
DATABASE_PASSWORD | データベースパスワード。SQLiteの場合不要 |
DATABASE_HOST | データーベースのホスト。設定しない場合、物理的に同じマシンとみなされる。SQLiteでは不要 |
SQLiteは、Pytho2.5以降に含まれる
<blockquote>SQLiteを指定した場合準備は不要。データベースファイルは必要になったときに作成される</blockquote>
PostgreSQLを利用してみる
DATABASE_ENGINE = 'postgresql_psycopg2' DATABASE_NAME = 'testdb' DATABASE_USER = 'postgres' DATABASE_PASSWORD = '******' DATABASE_HOST = DATABASE_PORT = '5432'
psycopg Python-PostgreSQL Database Adapterのインストール
http://www.initd.org/pub/software/psycopg/ http://www.initd.org/pub/software/psycopg/psycopg2-2.0.11.tar.gz
- 次のステップで、以下を行うとエラー
# python manage.py syncdb : raise ImproperlyConfigured("Error loading psycopg2 module: %s" % e)
django.core.exceptions.ImproperlyConfigured: Error loading psycopg2 module: No module named psycopg2
psycopg のインストール
# wget http://www.initd.org/pub/software/psycopg/psycopg2-2.0.11.tar.gz # tar zxvf psycopg2-2.0.11.tar.gz
- 解凍してできたディレクトリで、以下を実行
# python setup.py install
- インポートできるか?
#python >>> import psycopg2 Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/local/lib/python2.6/site-packages/psycopg2/__init__.py", line 60, in <module> from _psycopg import BINARY, NUMBER, STRING, DATETIME, ROWID ImportError: libpq.so.5: cannot open shared object file: No such file or directory
# LD_LIBRARY_PATH=/usr/local/pgsql/lib:$LD_LIBRARY_PATH
OK
syncdbの実行
PostgreSQLを起動しておく
#pg_ctl start
syncdbコマンドの実行
# python manage.py syncdb Creating table auth_permission Creating table auth_group Creating table auth_user Creating table auth_message Creating table django_content_type Creating table django_session Creating table django_site You just installed Django's auth system, which means you don't have any superusers defined. Would you like to create one now? (yes/no): yes Username (Leave blank to use 'root'): Error: That e-mail address is invalid. E-mail address: piroto@typea.info Password: Password (again): Superuser created successfully. Installing index for auth.Permission model Installing index for auth.Message model
- 上記テーブルが作成された
INSTALLED_APPS設定
INSTALLED_APPS = ( 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.sites', )
モデルの生成
アプリケーションの作成
- ここまでで、プロジェクト環境は作成された
- Djangoのアプリケーションは、Pythonのパッケージ
<blockquote>プロジェクトは設定のコレクションであり、アプリケーションは特定のWebサイト。プロジェクトは複数のアプリケーションを含み、アプリケーションは複数のプロジェクトに属すことができる</blockquote>
サンプルアプリケーション(polls)の作成
# python manage.py startapp polls
作成されるファイル
# tree ./polls ./polls |-- __init__.py |-- models.py `-- views.py
モデルの作成
- Django Web アプリケーションでは、モデルを定義する
- 単純なサンプルアプリケーション(poll)では、2つのモデル polls、choicesを作成する
- pollは、質問と発表日、choiceは選択テキストと同意への投票の2つのフィールドを持つ
- /polls/models.pyに記述
from django.db import models class Poll(models.Model): question = models.CharField(max_length=200) pub_date = models.DateField('date published') class Choice(models.Model): poll = models.ForeignKey(Poll) choice = models.CharField(max_length=200) votes = models.IntegerField()
モデルの開始
settings.pyを以下のように編集
INSTALLED_APPS = ( 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.sites', 'mysite.polls' )
DDLの確認~テーブルの生成
- Djangoは、pollsを含むmysiteを認識しているので、以下のコマンドを実行
- データベースを起動しておく
DDLを発行し、テープルを作成する
# python manage.py sql polls BEGIN; CREATE TABLE "polls_poll" ( "id" serial NOT NULL PRIMARY KEY, "question" varchar(200) NOT NULL, "pub_date" date NOT NULL ) ; CREATE TABLE "polls_choice" ( "id" serial NOT NULL PRIMARY KEY, "poll_id" integer NOT NULL REFERENCES "polls_poll" ("id") DEFERRABLE INITIALLY DEFERRED, "choice" varchar(200) NOT NULL, "votes" integer NOT NULL ) ; COMMIT;
テーブルの生成
# python manage.py syncdb Creating table polls_poll Creating table polls_choice Installing index for polls.Choice model
APIから操作してみる
- manage.pyを指定することで、プロジェクト環境が設定される
- mysiteをsys.pathに設定
- DJANGO_SETTINGS_MODULE 環境変数の設定
# python manage.py shell
Shellからdatabase APIを利用
>>> from mysite.polls.models import Poll,Choice #モデルとクラスのインポート #まだpollsは存在していない >>> Poll.objects.all() [] #pollを生成 >>> import datetime >>> p = Poll(question="What's up?",pub_date=datetime.datetime.now()) >>> p.save() >>> p.id 1L #Pythonの属性を経由してデータベースのカラムにアクセス >>> p.question "What's up?" >>> p.pub_date datetime.datetime(2009, 6, 16, 8, 54, 31, 757771) >>> p.save() #データベース上のpollを表示 >>> Poll.objects.all() [<Poll: Poll object>] >>>
__unicode__メソッドの追加
>>> Poll.objects.all() [<Poll: Poll object>]
- この出力では、このオブジェクトを表現するには役に立っていないので、polls/models.py のクラスに__unicode__メソッドを追加する
class Poll(models.Model): : def __unicode__(self): return self.question class Choice(models.Model): : def __unicode__(self): return self.choice
- 出力がこうなる
>>> Poll.objects.all() [<Poll: What's up?>]
カスタムメソッドの追加
- python通常のメソッドを追加して、簡単なデモ
import datetime class Poll(models.Model): : def was_published_today(self): return self.pub_date == datetime.date.today()
>>> from mysite.polls.models import Poll,Choice #Djangoは高機能なlookup APIを提供 >>> Poll.objects.filter(id=1) [<Poll: What's up?>] >>> Poll.objects.filter(question__startswith='What') [<Poll: What's up?>] >>> p = Poll.objects.get(id=1) #カスタムメソッドが動作することを確認 >>> p.was_published_today() True #INSERTステートメントの記述なしに、createの呼び出しでChoiceオブジェクトを生成する #外部キー制約を指定したのでchoice_set が有効 >>> p.choice_set.create(choice='Not much',votes=0) <Choice: Not much> >>> p.choice_set.create(choice='The sky',votes=0) <Choice: The sky> >>> c = p.choice_set.create(choice='Just hacking again',votes=0) >>> Choice.objects.filter(poll__pub_date__year=2009) [<Choice: Just hacking again>, <Choice: The sky>, <Choice: Not much>] >>> c = p.choice_set.filter(choice__startswith='Just hacking') >>> c.delete()
<blockquote>APIは自動的にリレーションシップ(参照整合性制約)をフォローする。アンダースコアの2重続きは、リレーションシップを区別する</blockquote>
[[Django 最初のアプリケーション 2]|[次]]
© 2006 矢木浩人