ページの作成
親となるページを選択してください。
親ページに紐づくページを子ページといいます。
例: 親=スポーツ, 子1=サッカー, 子2=野球
子ページを親ページとして更に子ページを作成することも可能です。
例: 親=サッカー, 子=サッカーのルール
親ページはいつでも変更することが可能なのでとりあえず作ってみましょう!
| この記事の要点 |
|
DATABASES 設定
# config/settings.py
# SQLite (デフォルト、 開発用)
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}
# PostgreSQL
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'mydb',
'USER': 'postgres',
'PASSWORD': 'pass',
'HOST': '127.0.0.1',
'PORT': '5432',
'CONN_MAX_AGE': 60, # 接続プール (秒)
'OPTIONS': {
'sslmode': 'require',
},
}
}
# MySQL
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'mydb',
'USER': 'root',
'PASSWORD': 'pass',
'HOST': '127.0.0.1',
'PORT': '3306',
'OPTIONS': {
'charset': 'utf8mb4',
'init_command': "SET sql_mode='STRICT_TRANS_TABLES'",
},
}
}
# 環境変数から(推奨)
import environ
env = environ.Env()
DATABASES = {
'default': env.db('DATABASE_URL'),
# postgres://user:pass@host:5432/dbname
}
マイグレーション
# モデル変更 → マイグレーションファイル作成
python manage.py makemigrations
# 出力例
# Migrations for 'blog':
# blog/migrations/0001_initial.py
# - Create model Article
# マイグレーション適用
python manage.py migrate
# 特定アプリのみ
python manage.py migrate blog
python manage.py migrate blog 0003 # 特定リビジョンへ
# マイグレーション一覧
python manage.py showmigrations
# 中身を SQL で確認
python manage.py sqlmigrate blog 0001
# ロールバック(一つ前へ)
python manage.py migrate blog 0002
# 完全ロールバック
python manage.py migrate blog zero
# マイグレーションファイル削除(要注意)
# blog/migrations/0001_initial.py を消すとローカルでは作り直せるが、
# 既に migrate 済の環境では django_migrations テーブルと不整合
Model 定義
# blog/models.py
from django.db import models
from django.contrib.auth.models import User
class Category(models.Model):
name = models.CharField(max_length=50, unique=True)
slug = models.SlugField(unique=True)
class Meta:
verbose_name_plural = "Categories"
def __str__(self):
return self.name
class Article(models.Model):
STATUS_CHOICES = [
('draft', '下書き'),
('published', '公開'),
]
title = models.CharField(max_length=200)
slug = models.SlugField(unique=True)
body = models.TextField()
category = models.ForeignKey(
Category,
on_delete=models.CASCADE,
related_name='articles',
)
author = models.ForeignKey(User, on_delete=models.PROTECT)
tags = models.ManyToManyField('Tag', blank=True)
status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='draft')
views = models.PositiveIntegerField(default=0)
published_at = models.DateTimeField(null=True, blank=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
ordering = ['-created_at']
indexes = [
models.Index(fields=['status', 'published_at']),
]
constraints = [
models.UniqueConstraint(
fields=['author', 'title'],
name='unique_author_title',
),
]
def __str__(self):
return self.title
QuerySet (CRUD)
from blog.models import Article, Category
from django.contrib.auth.models import User
# === Create ===
article = Article.objects.create(
title="Django 入門",
slug="django-intro",
body="...",
author=User.objects.get(username='taro'),
category=Category.objects.get(slug='tech'),
)
# あるいは
a = Article(title="...", body="...")
a.save()
# === Read ===
# 1件取得
art = Article.objects.get(pk=1) # 存在しないと DoesNotExist
art = Article.objects.filter(pk=1).first() # 存在しないと None
art = Article.objects.get_or_create(slug='intro', defaults={'title': '...'})
# 全件
all_articles = Article.objects.all()
# フィルタ
published = Article.objects.filter(status='published')
recent = Article.objects.filter(created_at__gte='2026-01-01')
search = Article.objects.filter(title__icontains='Django')
# 否定・OR
from django.db.models import Q
Article.objects.filter(~Q(status='draft'))
Article.objects.filter(Q(category__slug='tech') | Q(category__slug='news'))
# ソート・ページング
Article.objects.order_by('-created_at')[:10] # 最新 10 件
# 関連先 (ForeignKey)
art = Article.objects.select_related('author', 'category').get(pk=1)
art.author.username
art.category.name
# 関連先 (ManyToMany / 逆参照)
arts = Article.objects.prefetch_related('tags').all()
for art in arts:
print([t.name for t in art.tags.all()])
# 集約
from django.db.models import Count, Avg, Sum, Max
Category.objects.annotate(article_count=Count('articles'))
Article.objects.aggregate(total_views=Sum('views'))
# === Update ===
art = Article.objects.get(pk=1)
art.title = "新タイトル"
art.save()
# 一括更新(save() を呼ばない、 シグナルも飛ばない)
Article.objects.filter(status='draft').update(status='published')
# === Delete ===
art = Article.objects.get(pk=1)
art.delete()
# 一括削除
Article.objects.filter(status='draft').delete()
QuerySet ルックアップ(フィールド検索)
| ルックアップ | 意味 | 例 |
|---|---|---|
exact | 完全一致 (デフォルト) | filter(title__exact='Hello') |
iexact | 大文字小文字無視 | filter(slug__iexact='HELLO') |
contains / icontains | 部分一致 | filter(title__icontains='django') |
startswith / endswith | 前方/後方 | filter(slug__startswith='2026-') |
in | リスト内 | filter(id__in=[1, 2, 3]) |
gt / gte / lt / lte | 比較 | filter(views__gte=100) |
range | 範囲 | filter(created_at__range=(d1, d2)) |
isnull | NULL チェック | filter(published_at__isnull=True) |
year / month / day | 日付パーツ | filter(created_at__year=2026) |
生 SQL を実行する
# 1. Model.objects.raw() — Model インスタンスを返す
articles = Article.objects.raw(
'SELECT * FROM blog_article WHERE views > %s ORDER BY views DESC',
[100]
)
for art in articles:
print(art.title)
# 2. connection.cursor() — 完全な生クエリ
from django.db import connection
with connection.cursor() as cursor:
cursor.execute("""
SELECT category_id, COUNT(*) AS c
FROM blog_article
WHERE status = %s
GROUP BY category_id
""", ['published'])
for row in cursor.fetchall():
print(row)
# 辞書で取得
def dictfetchall(cursor):
columns = [col[0] for col in cursor.description]
return [dict(zip(columns, row)) for row in cursor.fetchall()]
with connection.cursor() as cursor:
cursor.execute("SELECT id, title FROM blog_article")
rows = dictfetchall(cursor)
トランザクション
from django.db import transaction, IntegrityError
# 1. デコレータ
@transaction.atomic
def transfer(from_acc, to_acc, amount):
from_acc.balance -= amount
from_acc.save()
to_acc.balance += amount
to_acc.save()
# 2. with 文
def create_order(user, items):
with transaction.atomic():
order = Order.objects.create(user=user)
for item in items:
OrderItem.objects.create(order=order, product=item)
# ここで例外が出れば全部ロールバック
# 3. ネスト(セーブポイント)
def complex_op():
with transaction.atomic(): # 外側
order = Order.objects.create()
try:
with transaction.atomic(): # 内側(セーブポイント)
send_email_log(order)
except SMTPException:
# 内側だけロールバック、 外側は継続
pass
# 4. select_for_update (行ロック)
with transaction.atomic():
account = Account.objects.select_for_update().get(pk=acc_id)
account.balance -= amount
account.save()
# 5. autocommit 切替(必要時のみ)
from django.db import transaction
transaction.set_autocommit(False)
try:
# 手動制御
Article.objects.create(...)
transaction.commit()
except:
transaction.rollback()
finally:
transaction.set_autocommit(True)
パフォーマンスのコツ
- N+1 問題対策:
select_related(FK は JOIN)、prefetch_related(M2M / 逆 FK は別クエリ) - 必要な列のみ:
.only('id', 'title')/.defer('body') - カウントは
.count():len(qs)は全件評価する - 存在チェックは
.exists():if qs:は全件評価する - 大量更新は
.update(): 1 件ずつ save() しない - bulk_create / bulk_update: 大量挿入
- インデックス: Meta.indexes で複合インデックス定義
- EXPLAIN:
qs.explain()で SQL プラン確認
FAQ
Q: migrations フォルダは git に入れる?
A: 入れます。 チーム全体で同じ DB スキーマを保証するため必須。
Q: スキーマを大幅変更したい
A: 開発初期なら全マイグレーション削除 + DB 削除 + makemigrations 再実行。 運用後はカスタムマイグレーションで段階的に。
Q: 複数 DB を使い分けたい
A: DATABASES に複数定義 → using('replica') で切替、 または DATABASE_ROUTERS で自動振り分け。
ページの作成
親となるページを選択してください。
親ページに紐づくページを子ページといいます。
例: 親=スポーツ, 子1=サッカー, 子2=野球
子ページを親ページとして更に子ページを作成することも可能です。
例: 親=サッカー, 子=サッカーのルール
親ページはいつでも変更することが可能なのでとりあえず作ってみましょう!
子ページ
同階層のページ
- 環境構築とプロジェクト/アプリの作成
- MVC(MVT)のそれぞれの使い方と説明
- データベースへの接続と操作
- Django Administration
- git管理
- エラー一覧
- バージョンの確認方法
- ログ出力方法
- SQLのログ出力方法
- ログのローテート設定
- settings.pyの定数にアクセスする方法
- 本番環境へのインストールとアプリのデプロイ(apache編)
- 本番環境へのインストールとアプリのデプロイ(nginx編)
- djangoアプリの本番の開始URLを変更する
- 静的(static)ファイルの置き場所と読み込み(画像、css、js )
- CSRFトークンをAjaxで使用する方法
- ajaxの使用例(POST編)
- ファイルのアップロードとファイルの名前
- クイックスタート/チュートリアル
- ログイン機能
- テンプレート側のログイン判定
- ビュー側のログイン判定
- 管理者ユーザーの作成/判定と管理画面
- モデルのjson化とレスポンス
- runserverでポートを指定する方法
- cronによるバッチ実行
- テンプレートで利用する共通のcontextを定義する方法
- プログラムが本番サーバーで反映されない場合の対処法
- APIの作成
- cron用コマンド・ファイルの作成
人気ページ
- 1 Eclipseで「サーバーに追加または除去できるリソースがありません。」の原因と対処法
- 2 tomcat の起動 / 停止ログと catalina.log・catalina.out の違い
- 3 JavaScript base URL 取得方法|window.location.origin と SSR/Node.js 対応
- 4 YouTube Data API v3 エラー一覧|403/400/404 の主要原因と切り分け
- 5 Spring Frameworkのアノテーション一覧
- 6 Laravel エラー一覧|500/Blade/DB 接続/ルーティングの代表エラー
- 7 3Dグラフィックスとは|モデリング/レンダリング/主要ソフトウェア (Blender / Maya)
- 8 【Spring】@Valueアノテーションとは
- 9 CATALINA_HOME の確認方法 (Linux / Mac)
- 10 【Spring】@Autowiredアノテーションとは
最近更新/作成されたページ
- Laravel キャッシュクリア完全ガイド(cache:clear / config:clear / 2026-05-18 07:42:07
- プロジェクトの作成と削除 2026-05-18 07:42:07
- インストール直後にNetbeansが反応しない 2026-05-18 07:42:07
- 動画やチャンネルの検索 2026-05-18 07:42:07
- APIキー取得方法 2026-05-18 07:42:07
- チャンネル情報の取得 2026-05-18 07:42:07
- API 入門 — Web API(REST / GraphQL / gRPC / 2026-05-18 07:42:07
- インストール(eclipseプラグイン) 2026-05-18 07:42:07
- Laravel「Dotenv values containing spaces must be surrounded 2026-05-18 07:42:07
- エラー一覧 2026-05-18 07:42:07
- curl: (51) SSL: certificate subject name '~' does not match 2026-05-18 07:42:07
- インストール方法(Windows版) 2026-05-18 07:42:07
- JSONから配列に変換 2026-05-18 07:42:07
- 処理を一定時間待つ 2026-05-18 07:42:07
- A non well formed numeric value encountered 2026-05-18 07:42:07
コメントを削除してもよろしいでしょうか?