Django ORM – 单表实例

以下是用中文详细讲解 Django ORM(对象关系映射)在单表操作中的使用指南,聚焦于单表实例的增删改查(CRUD)操作,涵盖常用查询方法、过滤器和最佳实践。我会保持简洁清晰,适合初学者和进阶用户,并提供实用示例,关键代码将包裹在 ““` 标签中以生成 artifact。如果你有特定问题或需要更深入的内容,请随时告知!


什么是 Django ORM?

Django ORM 是 Django 的核心组件,允许开发者通过 Python 对象操作数据库,而无需编写原生 SQL。单表操作指对单个模型(对应数据库中的一张表)进行增删改查。

  • 作用
  • 使用 Python 代码定义和操作数据库表。
  • 提供直观的查询 API,简化数据操作。
  • 支持多种数据库(如 SQLite、PostgreSQL)。
  • 特点
  • 基于模型类(继承 models.Model)。
  • 通过 objects 管理器执行查询。
  • 自动处理 SQL 注入安全。

1. 定义模型

假设我们有一个应用 myapp,定义一个单表模型 Item,表示商品。

示例:myapp/models.py

from django.db import models

class Item(models.Model):
    name = models.CharField(max_length=100, verbose_name='商品名称')
    price = models.DecimalField(max_digits=10, decimal_places=2, verbose_name='价格')
    description = models.TextField(blank=True, verbose_name='描述')
    is_active = models.BooleanField(default=True, verbose_name='是否上架')
    created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')

    def __str__(self):
        return self.name

    class Meta:
        db_table = 'items'  # 自定义表名
        ordering = ['-created_at']  # 默认按创建时间降序


from django.db import models

class Item(models.Model):
name = models.CharField(max_length=100, verbose_name=’商品名称’)
price = models.DecimalField(max_digits=10, decimal_places=2, verbose_name=’价格’)
description = models.TextField(blank=True, verbose_name=’描述’)
is_active = models.BooleanField(default=True, verbose_name=’是否上架’)
created_at = models.DateTimeField(auto_now_add=True, verbose_name=’创建时间’)

def __str__(self):
    return self.name

class Meta:
    db_table = 'items'  # 自定义表名
    ordering = ['-created_at']  # 默认按创建时间降序

“`python
from django.db import models

class Item(models.Model):
name = models.CharField(max_length=100, verbose_name=’商品名称’)
price = models.DecimalField(max_digits=10, decimal_places=2, verbose_name=’价格’)
description = models.TextField(blank=True, verbose_name=’描述’)
is_active = models.BooleanField(default=True, verbose_name=’是否上架’)
created_at = models.DateTimeField(auto_now_add=True, verbose_name=’创建时间’)

def __str__(self):
    return self.name

class Meta:
    db_table = 'items'  # 自定义表名
    ordering = ['-created_at']  # 默认按创建时间降序
- **说明**:
  - `CharField`、`DecimalField` 等定义表字段。
  - `verbose_name`:设置字段的显示名称(用于 Admin 或表单)。
  - `Meta` 类:自定义表名和默认排序。
  - 运行迁移命令创建表:
    ```bash
    python manage.py makemigrations
    python manage.py migrate
    ```

---

### 2. 单表 CRUD 操作
以下展示如何对 `Item` 模型进行增删改查操作。

#### 2.1 增(Create)
创建新记录的几种方法:

##### 示例:创建记录

python
from django.shortcuts import render
from .models import Item

def create_item(request):
# 方法 1:使用 create()
item1 = Item.objects.create(
name=’Python 编程书’,
price=59.99,
description=’一本深入浅出的 Python 教程’,
is_active=True
)

# 方法 2:实例化后保存
item2 = Item(
    name='Django 开发指南',
    price=79.99,
    description='学习 Django 的最佳书籍'
)
item2.save()

return render(request, 'myapp/success.html', {'message': '商品创建成功'})
- **说明**:
  - `create()`:直接创建并保存到数据库。
  - `save()`:先实例化对象,再保存。
  - 批量创建可用 `bulk_create()`:
    ```python
    Item.objects.bulk_create([
        Item(name='Book 1', price=29.99),
        Item(name='Book 2', price=39.99),
    ])
    ```

#### 2.2 查(Retrieve)
查询记录的常用方法。

##### 示例:查询记录

python
from django.shortcuts import render, get_object_or_404
from .models import Item

def item_list(request):
# 查询所有记录
all_items = Item.objects.all()

# 过滤记录
active_items = Item.objects.filter(is_active=True)

# 精确查询
item_by_name = Item.objects.filter(name='Python 编程书')

# 获取单条记录
item = get_object_or_404(Item, pk=1)  # 抛出 404 如果不存在
# 或者
item_first = Item.objects.filter(price__gt=50).first()  # 返回 None 如果不存在

# 排序
sorted_items = Item.objects.order_by('-price')

# 限制结果
top_5_items = Item.objects.all()[:5]

return render(request, 'myapp/item_list.html', {
    'items': active_items,
    'single_item': item,
})
- **常用查询方法**:
  - `all()`:返回所有记录。
  - `filter()`:返回匹配条件的记录集。
  - `get()`:返回单个记录,抛出异常如果不存在或多条。
  - `first()` / `last()`:返回第一条/最后一条记录。
  - `order_by()`:排序(`-` 表示降序)。
  - `count()`:返回记录数。
    ```python
    count = Item.objects.filter(is_active=True).count()
    ```

- **常用过滤器**:
  - `__exact`:精确匹配(默认)。
  - `__contains`:包含(大小写敏感)。
  - `__icontains`:包含(忽略大小写)。
  - `__gt` / `__gte`:大于/大于等于。
  - `__lt` / `__lte`:小于/小于等于。
  - `__in`:在列表中。
  - `__startswith` / `__endswith`:以...开头/结尾。
  - 示例:
    ```python
    expensive_items = Item.objects.filter(price__gte=50)
    books = Item.objects.filter(name__icontains='book')
    items_in_list = Item.objects.filter(price__in=[29.99, 59.99])
    ```

#### 2.3 改(Update)
更新现有记录。

##### 示例:更新记录

python
from django.shortcuts import render, get_object_or_404
from .models import Item

def update_item(request, pk):
item = get_object_or_404(Item, pk=pk)

if request.method == 'POST':
    # 方法 1:更新单个对象
    item.price = 69.99
    item.is_active = False
    item.save()

    # 方法 2:批量更新
    Item.objects.filter(name='Python 编程书').update(price=65.00)

    return render(request, 'myapp/success.html', {'message': '商品更新成功'})

return render(request, 'myapp/item_form.html', {'item': item})
- **说明**:
  - `save()`:更新单个对象。
  - `update()`:批量更新,直接生成 SQL,效率更高。
  - 注意:`update()` 不触发模型的 `save()` 方法。

#### 2.4 删(Delete)
删除记录。

##### 示例:删除记录

python
from django.shortcuts import render, get_object_or_404
from .models import Item

def delete_item(request, pk):
item = get_object_or_404(Item, pk=pk)

if request.method == 'POST':
    # 删除单个对象
    item.delete()

    # 或者批量删除
    Item.objects.filter(is_active=False).delete()

    return render(request, 'myapp/success.html', {'message': '商品删除成功'})

return render(request, 'myapp/confirm_delete.html', {'item': item})
- **说明**:
  - `delete()`:删除单个对象或查询集。
  - 删除后数据不可恢复,谨慎操作。

---

### 3. 模板和视图集成
以下是将 ORM 查询结果展示到前端的示例。

#### 示例:视图 `myapp/views.py`

python
from django.shortcuts import render, get_object_or_404, redirect
from .models import Item
from .forms import ItemForm

def item_list(request):
items = Item.objects.filter(is_active=True).order_by(‘-price’)
return render(request, ‘myapp/item_list.html’, {‘items’: items})

def item_detail(request, pk):
item = get_object_or_404(Item, pk=pk)
return render(request, ‘myapp/item_detail.html’, {‘item’: item})

def item_create(request):
if request.method == ‘POST’:
form = ItemForm(request.POST)
if form.is_valid():
form.save()
return redirect(‘item_list’)
else:
form = ItemForm()
return render(request, ‘myapp/item_form.html’, {‘form’: form})

#### 示例:表单 `myapp/forms.py`

python
from django import forms
from .models import Item

class ItemForm(forms.ModelForm):
class Meta:
model = Item
fields = [‘name’, ‘price’, ‘description’, ‘is_active’]
labels = {
‘name’: ‘商品名称’,
‘price’: ‘价格’,
‘description’: ‘描述’,
‘is_active’: ‘是否上架’,
}
widgets = {
‘description’: forms.Textarea(attrs={‘rows’: 4}),
}

#### 示例:模板 `myapp/templates/myapp/item_list.html`

html
{% extends ‘base.html’ %}

{% block content %}

商品列表

添加商品

  • {{ item.name }} – ¥{{ item.price }} {% if not item.is_active %}(已下架){% endif %}
  • 暂无商品

{% endblock %}

#### 示例:模板 `myapp/templates/myapp/item_detail.html`

html
{% extends ‘base.html’ %}

{% block content %}

{{ item.name }}

价格:¥{{ item.price }}

描述:{{ item.description|default:”无描述” }}

状态:{% if item.is_active %}上架{% else %}下架{% endif %}

创建时间:{{ item.created_at|date:”Y-m-d H:i” }}
返回列表
{% endblock %}

#### 示例:模板 `myapp/templates/myapp/item_form.html`

html
{% extends ‘base.html’ %}

{% block content %}

添加商品

{% csrf_token %} {{ form.as_p }} 保存
取消
{% endblock %}

---

### 4. URL 路由
将视图绑定到 URL。

#### 示例:`myapp/urls.py`

python
from django.urls import path
from . import views

app_name = ‘myapp’

urlpatterns = [
path(”, views.item_list, name=’item_list’),
path(‘items//’, views.item_detail, name=’item_detail’),
path(‘items/create/’, views.item_create, name=’item_create’),
]

#### 项目级:`myproject/urls.py`

python
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
path(‘admin/’, admin.site.urls),
path(”, include(‘myapp.urls’, namespace=’myapp’)),
]

---

### 5. 最佳实践
1. **查询优化**:
   - 使用 `filter()` 而非 `all()` 减少结果集。
   - 避免循环中查询数据库:
     ```python
     # 差:for item in Item.objects.all(): print(item.name)
     # 好:items = Item.objects.all().values('name')
     ```

2. **明确字段**:
   - 使用 `values()` 或 `only()` 限制返回字段:
     ```python
     names = Item.objects.values('name')
     items = Item.objects.only('name', 'price')
     ```

3. **异常处理**:
   - 使用 `get_object_or_404` 或 `try-except`:
     ```python
     try:
         item = Item.objects.get(pk=1)
     except Item.DoesNotExist:
         return render(request, 'myapp/error.html', {'message': '商品不存在'})
     ```

4. **安全性**:
   - 避免直接拼接 SQL,ORM 自动防止 SQL 注入。
   - 使用 `form.cleaned_data` 处理用户输入。

5. **调试查询**:
   - 查看生成的 SQL:
     ```python
     print(Item.objects.filter(price__gt=50).query)
     ```
   - 使用 Django Debug Toolbar 分析性能。

---

### 6. 常见问题
1. **查询返回空**:
   - 检查过滤条件是否正确。
   - 确认数据库是否有数据(`Item.objects.count()`)。

2. **DoesNotExist 异常**:
   - 使用 `first()` 或 `get_object_or_404` 替代 `get()`。
   - 示例:
     ```python
     item = Item.objects.filter(pk=999).first()  # 返回 None
     ```

3. **性能慢**:
   - 检查查询是否多次访问数据库。
   - 使用 `values()` 或 `count()` 减少开销。

4. **迁移未生效**:
   - 确认运行了 `makemigrations` 和 `migrate`。
   - 检查 `INSTALLED_APPS` 是否包含应用。

---

### 7. 运行项目
1. 确保模型迁移:

bash
python manage.py makemigrations
python manage.py migrate

2. 启动服务器:

bash
python manage.py runserver
“`

  1. 访问:
  • 商品列表:http://127.0.0.1:8000/
  • 商品详情:http://127.0.0.1:8000/items/1/
  • 添加商品:http://127.0.0.1:8000/items/create/

总结

Django ORM 提供强大的单表操作能力,通过 objects 管理器实现增删改查。create()filter()get()update()delete() 等方法覆盖了常见需求,结合过滤器(如 __gt__contains)支持复杂查询。遵循最佳实践(如优化查询、异常处理)可提高代码效率和安全性。

如果你需要更复杂的 ORM 示例(如多表关联、聚合查询)、特定功能的深入讲解,或调试 ORM 问题的方法,请告诉我!

类似文章

发表回复

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