详细介绍:数据库完整指南:从基础到 Django 集成

目录

  1. 数据库基础概念

  2. 关系型数据库

  3. Django 数据库配置

  4. Django 模型详解

  5. 数据库迁移

  6. 数据库查询

  7. 数据库关系

  8. 数据库优化

  9. 生产环境部署

数据库基础概念

什么是数据库?

数据库是结构化信息的集合,用于高效存储、管理和检索数据。

数据库类型

  • 关系型数据库: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
URLFieldURL字段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应用。

记住以下最佳实践:

  1. 合理设计数据库关系

  2. 为常用查询字段添加索引

  3. 使用select_related和prefetch_related优化查询

  4. 定期备份数据库

  5. 在生产环境使用连接池

  6. 监控数据库性能

  7. 使用迁移管理数据库结构变更

通过掌握这些数据库知识,您将能够构建出更加健壮和高效的Django应用。

posted on 2025-11-04 13:09  blfbuaa  阅读(2)  评论(0)    收藏  举报