Django 模型

以下是用中文详细讲解 Django 模型(Models)的指南,涵盖模型的定义、作用、常用字段类型、关系、查询、迁移以及最佳实践。我会保持简洁清晰,适合初学者和进阶用户,并提供实用示例。如果你有特定问题或需要更深入的内容,请随时告知!


什么是 Django 模型?

Django 模型是定义数据库结构的 Python 类,遵循 Django 的 ORM(对象关系映射)机制。每个模型类映射到数据库中的一张表,类的属性(字段)映射到表的列。

  • 作用
  • 定义数据结构(表、字段、关系)。
  • 提供 Pythonic 方式操作数据库(增删改查)。
  • 自动生成数据库迁移文件,同步模型与数据库。
  • 特点
  • 基于 Python 类,继承 django.db.models.Model
  • 支持多种数据库(SQLite、PostgreSQL、MySQL 等)。
  • 内置强大的查询 API。

1. 定义模型

模型通常定义在应用的 models.py 文件中。

示例:myapp/models.py

from django.db import models

class Category(models.Model):
    name = models.CharField(max_length=100)
    created_at = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return self.name

class Item(models.Model):
    name = models.CharField(max_length=100)
    description = models.TextField(blank=True)
    price = models.DecimalField(max_digits=10, decimal_places=2)
    category = models.ForeignKey(Category, on_delete=models.CASCADE)
    is_active = models.BooleanField(default=True)

    def __str__(self):
        return self.name
  • 说明
  • 每个类继承 models.Model
  • 字段(如 CharFieldDecimalField)定义表的列。
  • __str__ 方法定义对象的字符串表示,便于调试和管理后台显示。

常用字段类型

  • 文本
  • CharField(max_length):定长字符串(如用户名)。
  • TextField():长文本(如描述)。
  • 数字
  • IntegerField():整数。
  • DecimalField(max_digits, decimal_places):小数(如价格)。
  • FloatField():浮点数。
  • 日期/时间
  • DateField():日期。
  • DateTimeField():日期和时间。
  • TimeField():时间。
  • 参数:auto_now=True(每次保存更新)、auto_now_add=True(创建时设置)。
  • 布尔
  • BooleanField():真/假。
  • 关系(详见下文):
  • ForeignKey():一对多。
  • ManyToManyField():多对多。
  • OneToOneField():一对一。
  • 其他
  • FileField():文件上传。
  • ImageField():图片上传(需安装 Pillow)。
  • JSONField():存储 JSON 数据。

字段常用参数

  • max_length:字符串最大长度。
  • blank=True:允许表单字段为空(前端验证)。
  • null=True:允许数据库字段为 NULL(慎用)。
  • default:默认值。
  • unique=True:字段值唯一。
  • choices:限制字段值范围(如枚举)。
  STATUS_CHOICES = (
      ('draft', '草稿'),
      ('published', '已发布'),
  )
  status = models.CharField(max_length=20, choices=STATUS_CHOICES)

2. 模型关系

Django 支持三种主要数据库关系。

2.1 一对多(ForeignKey)

  • 定义ForeignKey(ToModel, on_delete)
  • 作用:表示一个模型实例关联到另一个模型的单个实例。
  • 示例:Item 属于一个 Category
  category = models.ForeignKey(Category, on_delete=models.CASCADE)
  • on_delete 选项
  • models.CASCADE:删除主表记录时,从表记录也删除。
  • models.PROTECT:阻止删除主表记录。
  • models.SET_NULL:从表字段置为 NULL(需 null=True)。
  • models.SET_DEFAULT:置为默认值。

2.2 多对多(ManyToManyField)

  • 定义ManyToManyField(ToModel)
  • 作用:表示多对多关系,Django 自动创建中间表。
  • 示例:一个 Item 可以有多个标签,一个标签可用于多个 Item
  tags = models.ManyToManyField('Tag')

2.3 一对一(OneToOneField)

  • 定义OneToOneField(ToModel, on_delete)
  • 作用:表示唯一关联(如用户与其个人资料)。
  • 示例:
  user = models.OneToOneField('auth.User', on_delete=models.CASCADE)

3. 数据库迁移

模型定义后,需通过迁移将结构同步到数据库。

  1. 生成迁移文件
   python manage.py makemigrations
  • 检查 models.py 的变化,生成迁移文件(如 migrations/0001_initial.py)。
  1. 应用迁移
   python manage.py migrate
  • 执行迁移文件,创建或更新数据库表。
  1. 查看迁移
   python manage.py showmigrations
  1. 调试迁移
  • sqlmigrate:查看迁移的 SQL 语句。
    bash python manage.py sqlmigrate myapp 0001

4. 查询数据库

Django 提供强大的 ORM 查询 API,通过模型的 objects 管理器操作数据库。

4.1 基本查询

  • 获取所有记录
  items = Item.objects.all()
  • 过滤
  active_items = Item.objects.filter(is_active=True)
  • 获取单条记录
  item = Item.objects.get(id=1)  # 抛出异常如果不存在
  item = Item.objects.filter(id=1).first()  # 返回 None 如果不存在

4.2 高级查询

  • 条件查询
  • filter(field__exact=value):精确匹配。
  • filter(field__contains='text'):包含文本。
  • filter(price__gte=10):大于等于。
  • 示例:
    python items = Item.objects.filter(price__gte=10, category__name='书籍')
  • 排序
  items = Item.objects.order_by('-price')  # 降序
  • 限制结果
  items = Item.objects.all()[:5]  # 前 5 条

4.3 关系查询

  • 访问关联对象
  item = Item.objects.get(id=1)
  category_name = item.category.name  # 访问 ForeignKey
  • 反向查询
  category = Category.objects.get(id=1)
  items = category.item_set.all()  # 获取所有关联的 Item

4.4 创建/更新/删除

  • 创建
  Item.objects.create(name='书', price=29.99, category=category)
  • 更新
  item = Item.objects.get(id=1)
  item.price = 39.99
  item.save()
  • 删除
  item = Item.objects.get(id=1)
  item.delete()

5. 在视图和模板中使用

视图(myapp/views.py

from django.shortcuts import render
from .models import Item

def item_list(request):
    items = Item.objects.filter(is_active=True)
    return render(request, 'myapp/item_list.html', {'items': items})

模板(myapp/templates/myapp/item_list.html

{% extends 'base.html' %}

{% block content %}
    <h1>商品列表</h1>
    <ul>
    {% for item in items %}
        <li>{{ item.name }} - ¥{{ item.price }} ({{ item.category.name }})</li>
    {% empty %}
        <li>暂无商品</li>
    {% endfor %}
    </ul>
{% endblock %}

6. 管理后台集成

将模型注册到 Django 管理后台,方便管理数据。

示例:myapp/admin.py

from django.contrib import admin
from .models import Category, Item

@admin.register(Category)
class CategoryAdmin(admin.ModelAdmin):
    list_display = ['name', 'created_at']  # 显示字段
    search_fields = ['name']  # 搜索字段

@admin.register(Item)
class ItemAdmin(admin.ModelAdmin):
    list_display = ['name', 'price', 'category', 'is_active']
    list_filter = ['is_active', 'category']  # 过滤器
    search_fields = ['name', 'description']
  • 作用
  • list_display:自定义列表页面显示的字段。
  • list_filter:添加过滤器。
  • search_fields:启用搜索功能。

访问 http://127.0.0.1:8000/admin/(需创建超级用户:python manage.py createsuperuser)即可管理数据。


7. 最佳实践

  1. 字段设计
  • 使用 blank=Truenull=True 区分表单和数据库行为。
  • 为外键设置 related_name 自定义反向查询名称:
    python category = models.ForeignKey(Category, on_delete=models.CASCADE, related_name='items')
  1. 模型组织
  • 一个模型负责单一功能,避免过于复杂。
  • 使用 Meta 类自定义表名、排序等: class Item(models.Model): name = models.CharField(max_length=100) class Meta: db_table = 'custom_items' # 自定义表名 ordering = ['-price'] # 默认排序</code></pre></li>
  1. 迁移管理
  • 定期清理无用迁移文件(squashmigrations)。
  • 多人协作时注意迁移冲突,合并后再提交。
  1. 性能优化
  • 使用 select_related() 优化一对多查询:
    python items = Item.objects.select_related('category').all()
  • 使用 prefetch_related() 优化多对多查询:
    python items = Item.objects.prefetch_related('tags').all()
  • 避免在循环中查询数据库。
  1. 安全性
  • 避免直接在模型中存储敏感信息(如密码)。
  • 使用 Django 内置用户模型(django.contrib.auth.models.User)处理认证。

8. 常见问题

  1. 迁移失败
  • 检查 models.py 是否有语法错误。
  • 删除 migrations/ 文件和数据库后重新迁移(开发环境)。
  1. 字段类型错误
  • 确保字段类型与实际数据匹配(如 DecimalField 用于货币)。
  • null=True 慎用,可能导致查询复杂化。
  1. 查询性能慢
  • 检查是否滥用 all() 或未优化关联查询。
  • 使用 Django Debug Toolbar 分析查询。

9. 完整示例

模型(myapp/models.py

from django.db import models

class Category(models.Model):
    name = models.CharField(max_length=100)

    def __str__(self):
        return self.name

class Item(models.Model):
    name = models.CharField(max_length=100)
    price = models.DecimalField(max_digits=10, decimal_places=2)
    category = models.ForeignKey(Category, on_delete=models.CASCADE, related_name='items')

    def __str__(self):
        return self.name

视图(myapp/views.py

from django.shortcuts import render
from .models import Item

def item_list(request):
    items = Item.objects.select_related('category').all()
    return render(request, 'myapp/item_list.html', {'items': items})

模板(myapp/templates/myapp/item_list.html

{% extends 'base.html' %}
{% block content %}
    <h1>商品列表</h1>
    <ul>
    {% for item in items %}
        <li>{{ item.name }} - ¥{{ item.price }} ({{ item.category.name }})</li>
    {% endfor %}
    </ul>
{% endblock %}

迁移

python manage.py makemigrations
python manage.py migrate

总结

Django 模型通过 ORM 简化数据库操作,定义数据结构(字段、关系)并提供强大的查询 API。正确配置字段、关系和迁移,结合视图和模板,可以快速构建数据驱动的应用。遵循最佳实践(如优化查询、合理设计模型)能提高开发效率和性能。

如果你需要更深入的内容(如高级查询、自定义模型方法、信号处理)或调试模型相关问题,请告诉我!

类似文章

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注