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
“`
- 访问:
- 商品列表:
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 问题的方法,请告诉我!