id = models.AutoField(primary_key=True)
create_time = models.DateTimeField('创建时间', default=timezone.now)
# auto_now=True 每当这个模型的实例(一条数据)被保存 / 更新时,该字段会自动被设置为当前的系统时间,且这个过程是完全自动的,无需你手动赋值。
update_time = models.DateTimeField('更新时间', auto_now=True)
top = models.IntegerField(null=True, verbose_name="帐号状态(0不置顶 1置顶)", default=0) # null=True, 字段可以存 NULL
state = models.IntegerField(null=True, verbose_name="帐号状态(0未审核 1已审核)", default=0) # null=True, 字段可以存 NULL
reads = models.IntegerField('阅读量', default=0)
abstract = models.CharField('摘要', max_length=300)
# 用户被删除后,其发布的文章没有保留意义, 也删除
author = models.ForeignKey('user.MyUser', on_delete=models.CASCADE, verbose_name='用户')
# 核心修改:CharField → TextField(支持长文本,无长度限制)
content = models.TextField('内容')
name = models.CharField(max_length=100, unique=True, verbose_name="名称") name唯一。
introduce = models.TextField('简介', default='暂无介绍') 如果没有主动给 introduce 字段赋值,Django 会自动将该字段的值设为‘暂无介绍’。obj_user = User(name=data["name"], email=data["email"], phonenumber=data["phonenumber"],
remark=data["remark"])
obj_user.password = 123456
obj_user.avatar = "/media/userAvatar/001.png"
obj_user.create_time = datetime.now().date()
# 优先使用 timezone.now() 而非 datetime.now(),确保时区一致性
obj_user.save() # save就是添加数据库
print(f"保存数据库id是{obj_user.id}")class ArticleType(models.Model): id = models.AutoField(primary_key=True) name = models.CharField(max_length=100, verbose_name="名称") # unique=True=不能是空 remark = models.CharField(max_length=500, verbose_name="备注") # 创建数据时自动记录当前时间(仅第一次保存生效) create_time = models.DateTimeField(auto_now_add=True, verbose_name="创建时间") # 每次更新数据时自动更新为当前时间 update_time = models.DateTimeField(auto_now=True, verbose_name="更新时间") # 添加 obj_articleType = ArticleType(name=name, remark=remark) obj_articleType.save() # save就是添加数据库 保存数据库 时间不对。 修改配置文件 # 语言设置(可选) LANGUAGE_CODE = 'zh-hans' # 时区设置为东八区 'Asia/Shanghai' TIME_ZONE = 'Asia/Shanghai' USE_I18N = True # 启用时区支持(必须为True) 这个地之前设置true 保存时间还是错的,设置False 保存时间对了。 USE_TZ = False
# 2. 构造User模型实例列表(不先调用save(),仅封装数据) user_obj_list = [] for data in data_list: # 构造单个User对象(和你单条逻辑一致,补充公共字段) obj_user = User( name=data["name"], email=data["email"], phonenumber=data["phonenumber"], remark=data["remark"] ) # 补充公共字段(批量数据的公共属性可统一赋值) obj_user.password = 123456 obj_user.avatar = "/media/userAvatar/001.png" # 优先使用 timezone.now(),确保时区一致性 obj_user.create_time = timezone.now().date() # 或 datetime.now().date()(非Django场景) # 将对象加入列表,暂不保存 user_obj_list.append(obj_user) # 3. 批量保存到数据库(核心:bulk_create()) if user_obj_list: # 先判断列表非空,避免无效操作 # bulk_create 接收模型实例列表,一次性插入所有数据 User.objects.bulk_create(user_obj_list)
obj_user = User(id=data["id"], email=data["email"], phonenumber=data["phonenumber"], remark=data["remark"], status=data["status"], avatar=data["avatar"]) # 优先使用 timezone.now() 而非 datetime.now(),确保时区一致性 obj_user.update_time = datetime.now().date() obj_user.save(update_fields=['email', 'phonenumber', 'avatar', 'update_time', 'remark', 'status']) # 这里还是建议全部更新。 obj_user.save() 敏感数据可以不更新。
book = BookInfo()
book.id = request.POST.get("id")
book.bookName = request.POST.get("name")
book.price = request.POST.get("price")
book.publishDate = request.POST.get("publishDate")
book.bookType_id = request.POST.get("bookType_id")
book.save()删除所有数据 BookInfo.objects.all().delete() #删除指定id数据 BookInfo.objects.get(id=1).dellete() #根据条件删除多条数据 BookInfo.objects.filter(price_gte=90).delete() #从user role 表删除 userid=? 的记录 UserRole.objects.filter(user_id=user_id).delete()
#查询全部
booList = BookInfo.objects.all()
# 只返回 id 和 name 字段(推荐)
type_list = list(ArticleType.objects.all().values('id', 'name'))
根据id查询
book = BookInfo.objects.get(id=3)#返回 单个数据 id=3
根据name 和 pwd查询
user = User.objects.get(name=name, password=password)
get()方法的工作原理
get()方法在设计上用于获取唯一一条记录的场景
它的核心行为准则是:
•找到1条记录:成功返回该模型对象。
•找到0条记录:抛出该模型类的 DoesNotExist异常
•找到2条或更多记录:抛出该模型类的 MultipleObjectsReturned异常
# 2. 根据用户ID获取所有关联的角色ID
# values_list('role_id', flat=True) 只取role_id字段,返回扁平列表
role_ids = UserRole.objects.filter(user_id=user_id).values_list('role_id', flat=True)
# 3. 根据角色ID获取所有关联的菜单ID(去重,避免重复菜单)
menu_ids = RoleMenu.objects.filter(role_id__in=role_ids).values_list('menu_id', flat=True).distinct()
#排序
menuQuerySet = Menu.objects.order_by("order_num")
#获取取数量
if Menu.objects.filter(parent_id=id).count() > 0:
filter查询
booList =BookInfo.objects.filter(id=2,price=100.01)
booList =BookInfo.objects.filter(id=2)
d = dict(id=2, price=100.01)
booList = BookInfo.objects.filter(**d)
filter 加 or 查询
booList = BookInfo.objects.filter(Q(id=1)|Q(price=100.01)) #这是or 查询 id=1 或者 price = 100.01
print(booList)
filter 加 不等于查询
booList = BookInfo.objects.filter(~Q(id=1)|Q(price=100.01)) #这是or 查询 id!=1 或者 price = 100.01
print(booList)
Exclued 返回不满足的条件。
booList = BookInfo.objects.exclude(id=1) #id != 1
print(booList)
#分页查询 还有搜索条件
# 这是数据集 不是序列化对象
userListPage = Paginator(User.objects.filter(name__icontains=query), pageSize).page(pageNum)
total = User.objects.filter(name__icontains=query).count()
obj_users = userListPage.object_list.values() # 转成字典 dict
users = list(obj_users) # 这个就是我们要的数据了。序列化的数据了。 把外层的容器换成list以下是整理后的 Django 高级查询匹配符 表格,结构更清晰易读:
| 匹配符 | 使用示例 | 说明 |
|---|---|---|
__exact | filter(job__exact="开发") | 精确等于,如 SQL 的like '开发' |
__iexact | filter(job__iexact="开发") | 精确等于并忽略大小写 |
__contains | filter(job__contains="开发") | 模糊匹配,如 SQL 的like '%开发%' |
__icontains | filter(job__icontains="开发") | 模糊匹配,忽略大小写 |
__gt | filter(job__gt=5) | 大于 |
__gte | filter(job__gte=5) | 大于等于 |
__lt | filter(job__lt=5) | 小于 |
__lte | filter(job__lte=5) | 小于等于 |
__in | filter(job__in=[1,2,3]) | 判断是否在列表内 |
__startswith | filter(job__startswith="开发") | 以…… 开头 |
__istartswith | filter(job__istartswith="开发") | 以…… 开头并忽略大小写 |
__endswith | filter(job__endswith="开发") | 以…… 结尾 |
__iendswith | filter(job__iendswith="开发") | 以…… 结尾并忽略大小写 |
__range | filter(job__range="开发") | 在…… 范围内(注:通常用于数值 / 日期范围,如__range=(1,5)) |
__year | filter(job__year=2018) | 日期字段的年份 |
__month | filter(job__month=12) | 日期字段的月份 |
__day | filter(job__day=30) | 日期字段的天数 |
__isnull | filter(job__isnull=True/False) | 判断是否为空 |

class Article(models.Model):
id = models.AutoField(primary_key=True)
title = models.CharField('标题', max_length=300)
# 分类 被删除后,其发布的文章没有保留意义, 也删除
type = models.ForeignKey(ArticleType, on_delete=models.CASCADE, verbose_name='博客类别')
# 核心修改:CharField → TextField(支持长文本,无长度限制)
content = models.TextField('内容')
# 用户被删除后,其发布的文章没有保留意义, 也删除
author = models.ForeignKey('user.MyUser', on_delete=models.CASCADE, verbose_name='用户')
top_article_list = Article.objects.filter(top=1, state=1).order_by('-create_time')[:5]
执行这行代码时,Django 只会:
1 查 Article 表的所有字段(包括 type_id,这是 Article 表自己的字段,不是 ArticleType 表的)
2 不会连接 ArticleType 表,也不会执行任何关于 ArticleType 的 SQL;
3 type_id 只是一个普通的数字(比如 1、2),和 top、state 字段没有本质区别,不会触发额外查询。
只有这 2 种情况,才会查 ArticleType 表
# 代码中访问 → 触发查询for article in top_article_list:
print(article.type.name) # 这里才会查 ArticleType 表
<!-- 模板中访问 → 触发查询 -->
{{ article.type.name }}
假如是返回json 数据。那么type 是什么。
def article_list_api(request):
# 查询文章(和之前一样,只查 Article 表)
article_list = Article.objects.filter(state=1).order_by('-create_time')[:10]
# 手动构造返回的字典(决定 JSON 包含哪些字段)
result = []
for article in article_list:
article_dict = {
"id": article.id,
"title": article.title,
"content": article.content,
"top": article.top,
"state": article.state,
# 情况1-1:只返回 type 的 ID(默认,不触发额外查询)
"type_id": article.type_id, # 直接取 Article 表的 type_id 字段,不查 ArticleType
# 情况1-2:返回 type 的完整信息(会触发额外查询)
# "type": {
# "id": article.type.id,
# "name": article.type.name, # 这里会查 ArticleType 表
# "desc": article.type.desc
# },
"create_time": article.create_time.strftime('%Y-%m-%d %H:%M:%S'),
"update_time": article.update_time.strftime('%Y-%m-%d %H:%M:%S')
}
result.append(article_dict)
# 返回 JSON 响应
return JsonResponse({"code": 200, "data": result})from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from django.http import JsonResponse
from datetime import datetime
def api_list(request):
# 1. 处理分页参数
try:
page = int(request.GET.get('page', 1))
page = page if page >= 1 else 1
except (ValueError, TypeError):
page = 1
try:
limit = int(request.GET.get('limit', 10))
# 限制limit范围:1-100,避免传0/负数/过大值导致性能问题
limit = limit if (0 < limit <= 100) else 10
except (ValueError, TypeError):
limit = 10 # 原代码这里是1,改为10更合理
# 2. 构建动态查询条件
# 先创建基础查询集
article_queryset = MyUser.objects.all()
# 2.1 处理state参数(状态过滤)
state = request.GET.get('state')
if state is not None:
try:
# 确保state是整数
state_int = int(state)
article_queryset = article_queryset.filter(state=state_int)
except (ValueError, TypeError):
# 若state参数格式错误,不添加该过滤条件
pass
# 2.2 处理q参数(关键词搜索,假设搜索用户名/标题等字段,你可根据实际字段调整)
q = request.GET.get('q')
if q and q.strip(): # 确保q不为空字符串
# 示例:搜索username或nickname包含关键词(可根据实际模型字段修改)
article_queryset = article_queryset.filter(
# 使用Q对象实现多字段模糊搜索,需要先导入:from django.db.models import Q
# Q(username__contains=q) | Q(nickname__contains=q)
username__contains=q # 简化版:只搜索username字段
)
# 构建多字段模糊搜索条件:只要任意一个字段包含关键词就匹配
article_queryset = article_queryset.filter(
Q(username__contains=q) | # 用户名
Q(name__contains=q) | # 姓名
Q(telephone__contains=q) | # 电话
Q(address__contains=q) | # 地址
Q(profession__contains=q) | # 职业
Q(company__contains=q) | # 公司
Q(introduce__contains=q) # 简介/介绍
)
# 2.3 处理type参数(原代码中的type=id,改为动态获取)
type_id = request.GET.get('type')
if type_id is not None:
try:
type_int = int(type_id)
article_queryset = article_queryset.filter(type=type_int)
except (ValueError, TypeError):
pass
# 2.4 处理时间范围参数(create_time1到create_time2)
create_time1 = request.GET.get('create_time1')
create_time2 = request.GET.get('create_time2')
time_range = []
# 解析开始时间
if create_time1:
try:
# 假设前端传的时间格式是:YYYY-MM-DD 或 YYYY-MM-DD HH:MM:SS
start_time = datetime.strptime(create_time1, '%Y-%m-%d %H:%M:%S')
time_range.append(start_time)
except ValueError:
try:
start_time = datetime.strptime(create_time1, '%Y-%m-%d')
time_range.append(start_time)
except ValueError:
pass
# 解析结束时间
if create_time2:
try:
end_time = datetime.strptime(create_time2, '%Y-%m-%d %H:%M:%S')
time_range.append(end_time)
except ValueError:
try:
end_time = datetime.strptime(create_time2, '%Y-%m-%d')
# 日期格式时,结束时间补到当天23:59:59
end_time = datetime.combine(end_time.date(), datetime.max.time())
time_range.append(end_time)
except ValueError:
pass
# 添加时间范围过滤
if len(time_range) == 2:
article_queryset = article_queryset.filter(create_time__range=time_range)
elif len(time_range) == 1:
# 只有开始时间:大于等于开始时间
article_queryset = article_queryset.filter(create_time__gte=time_range[0])
# 保持原有的排序
article_queryset = article_queryset.order_by('-create_time')
# 3. 分页处理
paginator = Paginator(article_queryset, limit)
user_list = None # 初始化变量
try:
user_list = paginator.page(page)
except EmptyPage:
# 页码超出范围,返回最后一页
user_list = paginator.page(paginator.num_pages)
page = paginator.num_pages
except PageNotAnInteger:
# 页码非数字,返回第1页
user_list = paginator.page(1)
page = 1
# 4. 序列化数据(注意:不能直接返回QuerySet,需要转为字典列表)
data = []
for item in user_list:
# 根据你的模型字段自定义返回的字段
data.append({
'id': item.id,
'username': item.username,
'state': item.state,
'type': item.type,
'create_time': item.create_time.strftime('%Y-%m-%d %H:%M:%S'),
# 添加其他需要返回的字段
})
# 5. 返回响应
return JsonResponse({
'code': 200,
'msg': '成功.',
'count': paginator.count, # 总记录数
'page': page, # 当前页码
'limit': limit, # 每页条数
'data': data
}, json_dumps_params={'ensure_ascii': False})
我可以用这样的返回list 简单一点
data = list(user_list.values()) list(user_list.values()) 虽然能序列化,但时间字段(如 create_time)会是 UTC 格式,前端展示不友好(可选优化)。
# (优化时间字段格式,可选) 把上面的data 注释掉 用这个。
if user_list and hasattr(user_list, 'object_list'):
# 有数据时格式化时间字段
data = []
for item in user_list:
item_dict = dict(item.__dict__)
# 移除不必要的内部属性
item_dict.pop('_state', None)
# 格式化时间字段(如果有create_time)
if 'create_time' in item_dict:
item_dict['create_time'] = item_dict['create_time'].strftime('%Y-%m-%d %H:%M:%S')
data.append(item_dict)
else:
# 无数据时返回空列表
data = []
user_list = paginator.page(paginator.num_pages) Page 对象
# 这个user_list 其实并不是QuerySet , 分页器返回的 Page 分页对象
# 1. 先拿到分页对象中的数据列表(object_list 是 QuerySet) 不然我们遍历一次 后面就报错了。
# 原因 user_list 是「分页对象」,遍历后迭代器已耗尽
user_object_list = user_list.object_list
data = list(user_object_list.values())
booList = BookInfo.objects.all() QuerySet 对象
list2 = UserRole.objects.filter(user_id=user_id) QuerySet 对象
list2.values() 而是返回一个 ValuesQuerySet(QuerySet 的子类),其中每个元素是 dict;
data = list(list2.values()) 列表里的每一项都是字典(dict)站长微信:xiaomao0055
站长QQ:14496453