目录
-
数据库基础概念
-
关系型数据库
-
Django 数据库配置
-
Django 模型详解
-
数据库迁移
-
数据库查询
-
数据库关系
-
数据库优化
-
生产环境部署
数据库基础概念
什么是数据库?
数据库是结构化信息的集合,用于高效存储、管理和检索数据。
数据库类型
-
关系型数据库:MySQL、PostgreSQL、SQLite
-
非关系型数据库:MongoDB、Redis
-
时序数据库:InfluxDB
-
图数据库:Neo4j
ACID 原则
-
原子性:事务要么全部完成,要么全部不完成
-
一致性:事务必须使数据库从一种一致状态变为另一种一致状态
-
隔离性:并发事务之间互不干扰
-
持久性:事务完成后,对数据库的修改是永久的
关系型数据库
核心概念
sql
-- 数据库操作
CREATE DATABASE mydb;
USE mydb;
-- 表操作
CREATE TABLE users (
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) UNIQUE NOT NULL,
email VARCHAR(100) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 数据操作
INSERT INTO users (username, email) VALUES ('john', 'john@example.com');
SELECT * FROM users WHERE username = 'john';
UPDATE users SET email = 'new@example.com' WHERE id = 1;
DELETE FROM users WHERE id = 1;
常见关系型数据库比较
数据库 | 特点 | 适用场景 |
---|---|---|
MySQL | 流行、成熟、社区强大 | Web应用、中小型系统 |
PostgreSQL | 功能丰富、标准兼容性好 | 复杂应用、地理数据 |
SQLite | 轻量级、零配置 | 移动应用、小型项目 |
Oracle | 企业级、功能强大 | 大型企业系统 |
Django 数据库配置
基本配置
python
# settings.py
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}
PostgreSQL 配置
python
# settings.py
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'mydatabase',
'USER': 'mydatabaseuser',
'PASSWORD': 'mypassword',
'HOST': 'localhost',
'PORT': '5432',
'CONN_MAX_AGE': 600, # 连接存活时间(秒)
'OPTIONS': {
'connect_timeout': 10,
}
}
}
MySQL 配置
python
# settings.py
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'mydatabase',
'USER': 'mydatabaseuser',
'PASSWORD': 'mypassword',
'HOST': 'localhost',
'PORT': '3306',
'OPTIONS': {
'charset': 'utf8mb4',
'init_command': "SET sql_mode='STRICT_TRANS_TABLES'",
},
'TEST': {
'CHARSET': 'utf8mb4',
'COLLATION': 'utf8mb4_unicode_ci',
}
}
}
多数据库配置
python
# settings.py
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'primary_db',
# ... 其他配置
},
'read_replica': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'replica_db',
# ... 其他配置
},
'logging': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'logs.db',
}
}
# 数据库路由
DATABASE_ROUTERS = ['myapp.routers.DatabaseRouter']
Django 模型详解
基础模型定义
python
# models.py
from django.db import models
from django.urls import reverse
from django.core.validators import MinLengthValidator, MaxValueValidator
class TimestampModel(models.Model):
"""抽象基类,提供时间戳字段"""
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
abstract = True
class User(TimestampModel):
# 字段类型
username = models.CharField(
max_length=50,
unique=True,
validators=[MinLengthValidator(3)],
verbose_name='用户名'
)
email = models.EmailField(unique=True, verbose_name='邮箱')
age = models.PositiveIntegerField(
null=True,
blank=True,
validators=[MaxValueValidator(150)],
verbose_name='年龄'
)
is_active = models.BooleanField(default=True, verbose_name='是否激活')
birth_date = models.DateField(null=True, blank=True, verbose_name='出生日期')
salary = models.DecimalField(
max_digits=10,
decimal_places=2,
null=True,
blank=True,
verbose_name='薪资'
)
bio = models.TextField(blank=True, verbose_name='个人简介')
avatar = models.ImageField(
upload_to='avatars/',
null=True,
blank=True,
verbose_name='头像'
)
# 元数据
class Meta:
verbose_name = '用户'
verbose_name_plural = '用户'
ordering = ['-created_at']
indexes = [
models.Index(fields=['username']),
models.Index(fields=['email', 'is_active']),
]
constraints = [
models.CheckConstraint(
check=models.Q(age__gte=0),
name='age_positive'
)
]
def __str__(self):
return self.username
def get_absolute_url(self):
return reverse('user_detail', kwargs={'pk': self.pk})
@property
def display_name(self):
return f"{self.username} ({self.email})"
def save(self, *args, **kwargs):
# 保存前的自定义逻辑
self.email = self.email.lower()
super().save(*args, **kwargs)
字段类型详解
字段类型 | 说明 | 对应数据库类型 |
---|---|---|
CharField | 字符串字段 | VARCHAR |
TextField | 大文本字段 | TEXT |
IntegerField | 整数字段 | INTEGER |
DecimalField | 十进制数字段 | NUMERIC |
BooleanField | 布尔字段 | BOOLEAN |
DateTimeField | 日期时间字段 | DATETIME |
DateField | 日期字段 | DATE |
TimeField | 时间字段 | TIME |
EmailField | 邮箱字段 | VARCHAR |
URLField | URL字段 | VARCHAR |
FileField | 文件字段 | VARCHAR |
ImageField | 图片字段 | VARCHAR |
字段选项
python
class ExampleModel(models.Model):
# 常用字段选项
name = models.CharField(
max_length=100,
null=True, # 数据库允许NULL
blank=True, # 表单验证允许空值
default='Unknown', # 默认值
unique=True, # 唯一值
db_index=True, # 创建索引
choices=[ # 选择项
('draft', '草稿'),
('published', '已发布'),
],
help_text='请输入名称', # 帮助文本
verbose_name='名称' # 可读名称
)
数据库迁移
迁移命令
bash
# 创建迁移文件
python manage.py makemigrations
# 查看迁移SQL
python manage.py sqlmigrate myapp 0001
# 应用迁移
python manage.py migrate
# 查看迁移状态
python manage.py showmigrations
# 撤销迁移
python manage.py migrate myapp 0001
# 数据迁移
python manage.py makemigrations --empty myapp
自定义迁移
python
# myapp/migrations/0002_custom_migration.py
from django.db import migrations, models
def add_default_categories(apps, schema_editor):
Category = apps.get_model('myapp', 'Category')
Category.objects.bulk_create([
Category(name='技术'),
Category(name='生活'),
Category(name='旅游'),
])
def remove_default_categories(apps, schema_editor):
Category = apps.get_model('myapp', 'Category')
Category.objects.filter(name__in=['技术', '生活', '旅游']).delete()
class Migration(migrations.Migration):
dependencies = [
('myapp', '0001_initial'),
]
operations = [
migrations.RunPython(
add_default_categories,
remove_default_categories
),
]
数据库查询
基础查询
python
from myapp.models import User, Post
from django.db.models import Q, Count, Avg, Sum
# 创建
user = User.objects.create(username='john', email='john@example.com')
# 查询所有
users = User.objects.all()
# 过滤查询
active_users = User.objects.filter(is_active=True)
john_users = User.objects.filter(username__contains='john')
recent_users = User.objects.filter(created_at__gte='2024-01-01')
# 排除查询
inactive_users = User.objects.exclude(is_active=True)
# 获取单个对象
try:
user = User.objects.get(id=1)
except User.DoesNotExist:
user = None
# 快捷方法
user = User.objects.filter(id=1).first()
# 复杂查询
complex_query = User.objects.filter(
Q(is_active=True) &
(Q(username__startswith='j') | Q(email__contains='example'))
)
# 排序
users_ordered = User.objects.order_by('-created_at', 'username')
# 切片
recent_10_users = User.objects.order_by('-created_at')[:10]
高级查询方法
python
# 聚合查询
from django.db.models import Count, Avg, Max, Min
stats = User.objects.aggregate(
total_users=Count('id'),
avg_age=Avg('age'),
max_salary=Max('salary')
)
# 分组查询
user_posts_count = User.objects.annotate(
post_count=Count('posts')
).filter(post_count__gt=0)
# 值列表
usernames = User.objects.values_list('username', flat=True)
user_data = User.objects.values('username', 'email')
# 选择相关对象(减少查询)
users_with_posts = User.objects.select_related('profile').prefetch_related('posts')
# 原生SQL查询
from django.db import connection
with connection.cursor() as cursor:
cursor.execute("SELECT * FROM myapp_user WHERE age > %s", [18])
rows = cursor.fetchall()
# 使用raw方法
users = User.objects.raw('SELECT * FROM myapp_user WHERE is_active = %s', [True])
查询性能优化
python
# 不好的查询 - N+1 问题
users = User.objects.all()
for user in users:
print(user.profile.bio) # 每次循环都会查询数据库
# 好的查询 - 使用select_related
users = User.objects.select_related('profile').all()
for user in users:
print(user.profile.bio) # 一次性查询
# 使用prefetch_related处理多对多关系
posts = Post.objects.prefetch_related('tags').all()
for post in posts:
print(post.tags.all()) # 一次性预加载
数据库关系
一对一关系
python
class UserProfile(models.Model):
user = models.OneToOneField(
User,
on_delete=models.CASCADE,
related_name='profile'
)
bio = models.TextField(blank=True)
location = models.CharField(max_length=100, blank=True)
def __str__(self):
return f"{self.user.username}的档案"
# 使用示例
user = User.objects.get(id=1)
profile = user.profile # 通过related_name访问
一对多关系
python
class Post(TimestampModel):
author = models.ForeignKey(
User,
on_delete=models.CASCADE,
related_name='posts'
)
title = models.CharField(max_length=200)
content = models.TextField()
is_published = models.BooleanField(default=False)
class Meta:
ordering = ['-created_at']
def __str__(self):
return self.title
# 使用示例
user = User.objects.get(id=1)
user_posts = user.posts.all() # 用户的所有文章
latest_post = user.posts.first()
多对多关系
python
class Tag(models.Model):
name = models.CharField(max_length=50, unique=True)
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.name
class Post(TimestampModel):
# ... 其他字段
tags = models.ManyToManyField(
Tag,
related_name='posts',
blank=True
)
def get_tag_names(self):
return list(self.tags.values_list('name', flat=True))
# 使用示例
post = Post.objects.get(id=1)
post.tags.add(tag1, tag2) # 添加标签
post.tags.remove(tag1) # 移除标签
post.tags.clear() # 清空所有标签
自定义中间表
python
class PostTag(models.Model):
post = models.ForeignKey(Post, on_delete=models.CASCADE)
tag = models.ForeignKey(Tag, on_delete=models.CASCADE)
added_by = models.ForeignKey(User, on_delete=models.CASCADE)
added_at = models.DateTimeField(auto_now_add=True)
class Meta:
unique_together = ['post', 'tag']
class Post(models.Model):
tags = models.ManyToManyField(
Tag,
through='PostTag',
related_name='posts'
)
数据库优化
索引优化
python
class User(models.Model):
username = models.CharField(max_length=50, db_index=True)
email = models.EmailField(unique=True)
class Meta:
indexes = [
models.Index(fields=['username', 'email']),
models.Index(fields=['-created_at']),
]
查询优化技巧
python
# 1. 使用only和defer选择特定字段
users = User.objects.only('username', 'email') # 只查询指定字段
users = User.objects.defer('bio') # 排除指定字段
# 2. 使用exists检查存在性
if User.objects.filter(username='john').exists():
# 处理逻辑
# 3. 使用count获取数量
user_count = User.objects.count()
# 4. 使用bulk操作
users = [User(username=f'user{i}') for i in range(1000)]
User.objects.bulk_create(users) # 批量创建
# 5. 使用update批量更新
User.objects.filter(is_active=False).update(is_active=True)
数据库连接池
python
# 使用django-db-connection-pool
DATABASES = {
'default': {
'ENGINE': 'dj_db_conn_pool.backends.mysql',
'NAME': 'mydatabase',
'POOL_OPTIONS': {
'POOL_SIZE': 10,
'MAX_OVERFLOW': 20,
'RECYCLE': 3600,
}
}
}
生产环境部署
数据库备份
python
# management/commands/backup_database.py
from django.core.management.base import BaseCommand
from django.conf import settings
import subprocess
import os
from datetime import datetime
class Command(BaseCommand):
help = '备份数据库'
def handle(self, *args, **options):
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
backup_file = f'backup_{timestamp}.sql'
if settings.DATABASES['default']['ENGINE'] == 'django.db.backends.postgresql':
cmd = [
'pg_dump',
'-h', settings.DATABASES['default']['HOST'],
'-U', settings.DATABASES['default']['USER'],
'-d', settings.DATABASES['default']['NAME'],
'-f', backup_file
]
env = os.environ.copy()
env['PGPASSWORD'] = settings.DATABASES['default']['PASSWORD']
subprocess.run(cmd, env=env)
self.stdout.write(
self.style.SUCCESS(f'备份完成: {backup_file}')
)
数据库监控
python
# 使用Django Debug Toolbar
INSTALLED_APPS = [
# ...
'debug_toolbar',
]
MIDDLEWARE = [
'debug_toolbar.middleware.DebugToolbarMiddleware',
# ...
]
# 数据库查询日志
LOGGING = {
'version': 1,
'handlers': {
'console': {
'level': 'DEBUG',
'class': 'logging.StreamHandler',
},
},
'loggers': {
'django.db.backends': {
'level': 'DEBUG',
'handlers': ['console'],
}
}
}
生产环境配置
python
# settings/production.py
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': os.getenv('DB_NAME'),
'USER': os.getenv('DB_USER'),
'PASSWORD': os.getenv('DB_PASSWORD'),
'HOST': os.getenv('DB_HOST'),
'PORT': os.getenv('DB_PORT', '5432'),
'CONN_MAX_AGE': 600,
'OPTIONS': {
'sslmode': 'require',
}
}
}
# 数据库性能配置
DATABASES['default']['ATOMIC_REQUESTS'] = False # 提高性能
DATABASES['default']['AUTOCOMMIT'] = True
数据库健康检查
python
# health_checks.py
from django.db import connection
from django.http import JsonResponse
def database_health_check(request):
try:
with connection.cursor() as cursor:
cursor.execute("SELECT 1")
result = cursor.fetchone()
if result[0] == 1:
return JsonResponse({'status': 'healthy'})
else:
return JsonResponse({'status': 'unhealthy'}, status=500)
except Exception as e:
return JsonResponse({'status': 'error', 'message': str(e)}, status=500)
总结
数据库是Web应用的核心组件,正确的数据库设计和优化对应用性能至关重要。Django提供了强大的ORM系统,使得数据库操作更加简单和安全。通过合理的模型设计、查询优化和适当的数据库配置,可以构建出高性能、可扩展的Web应用。
记住以下最佳实践:
-
合理设计数据库关系
-
为常用查询字段添加索引
-
使用select_related和prefetch_related优化查询
-
定期备份数据库
-
在生产环境使用连接池
-
监控数据库性能
-
使用迁移管理数据库结构变更
通过掌握这些数据库知识,您将能够构建出更加健壮和高效的Django应用。