最近搜索

python django 操作数据库

浏览:97
管理员 2026-01-05 00:01


数据库常用字段属性

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 高级查询匹配符 表格,结构更清晰易读:

匹配符使用示例说明
__exactfilter(job__exact="开发")精确等于,如 SQL 的like '开发'
__iexactfilter(job__iexact="开发")精确等于并忽略大小写
__containsfilter(job__contains="开发")模糊匹配,如 SQL 的like '%开发%'
__icontainsfilter(job__icontains="开发")模糊匹配,忽略大小写
__gtfilter(job__gt=5)大于
__gtefilter(job__gte=5)大于等于
__ltfilter(job__lt=5)小于
__ltefilter(job__lte=5)小于等于
__infilter(job__in=[1,2,3])判断是否在列表内
__startswithfilter(job__startswith="开发")以…… 开头
__istartswithfilter(job__istartswith="开发")以…… 开头并忽略大小写
__endswithfilter(job__endswith="开发")以…… 结尾
__iendswithfilter(job__iendswith="开发")以…… 结尾并忽略大小写
__rangefilter(job__range="开发")在…… 范围内(注:通常用于数值 / 日期范围,如__range=(1,5)
__yearfilter(job__year=2018)日期字段的年份
__monthfilter(job__month=12)日期字段的月份
__dayfilter(job__day=30)日期字段的天数
__isnullfilter(job__isnull=True/False)判断是否为空


image.png




查询一对一  一般情况是不查的 对面的表的

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