Django ORM

pycharm连接数据库

"""
三个位置查找数据库相关
    右侧上方database
    左下方databases
    配置里面的plugins插件搜索安装
    
    再没有卸载pycharm重新装
    
pycharm可以充当很多款数据库软件的客户端
参考视频:https://www.bilibili.com/video/BV1Sp4y1U7Jr?p=699&spm_id_from=pageDriver
需要提前创建好库

"""

 

django连接数据库

# 默认用的是sqlites3
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}

# djingo链接MySQL
    1、第一步配置文件中配置
    DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'day60',
        'USER':'root',
        'PASSWORD':'123456',
        'HOST':'127.0.0.1',
        'PORT':3306,
        'CHARSET':'utf8'
    }
}
    2、代码声明
    django默认用的是mysqldb模块链接MySQL
    但是该模块的兼容性不好 需要手动改为pymysql链接
    
    你需要告诉django不要用默认的mysql还是用pymysql
    # 在项目名下的init或者任意的应用名下的init文件中书写以下代码都可以
    import pymysql
    pymysql.install_as_MySQLdb()

 

Django ORM简介

ORM

"""
ORM  对象关系映射
作用:能够让一个不用sql语句的小白也能够通过python 面向对象的代码简单快捷的操作数据库
不足之处:封装程度太高  有时候sql语句的效率偏低  需要你自己写sql语句

类                         表

对象                      记录

对象属性                  记录某个字段对应的值

"""

 

应用下面的models.py文件

# 1、先去modles.py中书写一个类
class User(models.Model):
    # id int primary_key auto_increment
    id = models.AutoField(primary_key=True)
    # username varchar(32)
    username = models.CharField(max_length=32)
    # password int
    password = models.IntegerField()
    
*********************# 2、数据库迁移命令***************************
python3 manage.py makemigrations  # 将操作记录 记录到小本本上(migrations文件夹)

python3 manage.py migrate  # 将操作真正同步到数据库中
****************************************************************

# 只要你修改了models.py中跟数据库相关的代码  就必须重新执行上述的两条命令


class User(models.Model):
    # id int primary_key auto_increment
    id = models.AutoField(primary_key=True)
    # username varchar(32)
    username = models.CharField(max_length=32,verbose_name='用户名')
    
    """
    CharField必须要指定max_length参数  不指定会直接报错
    verbose_name该参数是所有字段都有的 就是对该字段的解释
    """
    
    # password int
    password = models.IntegerField(verbose_name='密码')


class Author(models.Model):
    # 由于一张表中必须要有一个主键字段  并且一般情况下都叫id字段
    # 所以ORM当你不定义主键字段的时候 ORM会自动帮你创建一个名为id主键字段
    # 也就意味着 后续我们在创建模型表的时候如果主键字段名没有额外的叫法 那么主键字段可以省略不写
    # username varchar(32)
    username = models.CharField(max_length=32)
    # password int
    password = models.IntegerField()

 

 

 

利用ORM实现数据的增删改查操作

字段的增删改查

# 字段的增加
    1、可以在终端内直接给出默认值
    2、该字段可以为空
    info = models.CharField(max_length=32,verbose_name='个人简介',null=True)
    3、直接给字段设置默认值
    hobby = models.CharField(max_length=32,verbose_name='兴趣爱好',default='study')
    
   
# 字段的修改
    直接修改代码  然后执行数据库迁移的两条命令即可!
    
  
# 字段的删(不要轻易操作)
    直接注释对应的字段  然后执行数据库迁移的两条命令即可!
    执行完毕之后  字段对应的数据也都没有了
    
"""
在操作models.py的时候一定要细心
    千万不要注释一些字段
    执行迁移命令之前最好先检查一下自己写的代码
"""

# 个人建议 当你离开你的计算机之后一定要锁屏

 

数据的增删改查

# 今天只会介绍一点点 后面会详细的介绍

#
res = models.User.objects.filter(username=username)
"""
不存在则返回None

返回值你先看成是列表套数据对象的格式
它也支持索引取值 切片操作  但是不支持负数索引
它也不推荐你使用索引的方式取值
user_obj = models.User.objects.filter(username=username).first()
"""

filter括号内可以携带多个参数 参数与参数之间默认是and关系
你可以把filter联想成where记忆


#
 # 第一种增加
from app01 import models
res = models.User.objects.create(username=username,password=password)
# 返回值就是当前被创建的对象本身
print(res,res.username,res.password)

 # 第二种增加
from app01 import models
user_obj = models.User(username=username,password=password)
user_obj.save()  # 保存数据

 

数据的增删改查(2)

# 先将数据库中的数据全部展示到前端  然后给每一个数据两个按钮  一个编辑 一个删除


# 查看
# 展示用户列表
def user_list(request):
    from app01 import models
    # # 查询出用户表里面所有的数据
    # # 方式1
    # data = models.User.objects.filter()
    # print(data)

    # 方式2
    # select * from user; 
    user_queryset = models.User.objects.all()

    # 以下两种方式都可以
    # return render(request,'userlist.html',{'user_queryset':user_queryset})
    return render(request,'userlist.html',locals())



# 编辑功能
    # 点击编辑按钮朝后端发送编辑数据的请求
    """
    如何告诉后端用户想要编辑哪一条数据?
        将编辑按钮所在的那一行数据的主键值发送给后端
        利用url问号后面携带参数的形式
    
     <tbody>
         {% for user_obj in user_queryset %}
             <tr>
                 <td>{{ user_obj.id }}</td>
                 <td>{{ user_obj.username }}</td>
                <td>{{ user_obj.password }}</td>
                 <td>
                     <a href="/edit_user/?user_id={{ user_obj.id }}" class="btn btn-primary btn-xs">编辑</a>
                     <a href="" class="btn btn-danger btn-xs">删除</a>
                 </td>
             </tr>
         {% endfor %}
     </tbody>
        
    """
    # 后端查询出用户想要编辑的数据对象 展示到前端页面供用户查看和编辑 
    
# 编辑用户
def edit_user(request):
    # 获取url问号后面的参数
    edit_id = request.GET.get('user_id')
    # 查询当前用户想要编辑数据对象
    edit_obj = models.User.objects.filter(id=edit_id).first()

    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')
        # 去数据库中修改对应的数据内容
        # 修改数据方式一
        # models.User.objects.filter(id=edit_id).update(username=username,password=password)
        """
               将filter查询出来的列表中所有的对象全部更新    批量更新操作
               只修改被修改的字段
        """
       
        # 修改数据方式二
        edit_obj.username = username
        edit_obj.password = password
        edit_obj.save()
        """
            上述方法当字段特别多的时候效率会非常低
            从头到尾将数据的所有字段全部更新一遍  无论该字段是否被修改
        """

       
        # 跳转到数据的展示页面
        return redirect('/userlist/')

    # 将数据对象展示到页面上
    return render(request,'edit_user.html',locals())

    

# 删除功能
"""
跟编辑功能逻辑类似

# 删除用户
def delete_user(request):
    # 获取用户想要删除的数据id值
    delete_id = request.GET.get('user_id')
    # 直接去数据库中找到对应的数据删除即可
    models.User.objects.filter(id=delete_id).delete()
    """
        批量删除
    """
    # 跳转到展示页面
    return redirect('/userlist/')
"""

# 真正的删除功能应该需要二次确认  我们这里先不做后面会讲
# 删除数据内部其实并不是真正的删除   我们会给数据添加一个标识字段用来表示当前数据是否被删除了,这里数据被删除了仅仅只是将字段修改了一个状态
    username  password  is_delete
      jason     123          0
      egon      123          1

 

djangoORM如何创建表关系

"""
表与表之间的关系
    没有关系    
        
    一对多
    
    多对多
     
    一对一

判断表关系的方法:换位思考
"""

图书表

出版社表

作者表

作者详情表

"""
图书和出版社是一对多的关系 外键字段建在多的那一方 book

图书和作者是多对多的关系  需要创建第三张表来专门存储

作者与作者详情表 是一对一的
"""

from django.db import models

# Create your models here.

# 创建表关系 先将基表创建出来 然后再添加外键字段
# 图书表
class Book(models.Model):
    title = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=8,decimal_places=2)
    # 小数总共八位  小数点后面占两位
    """
    图书和出版社是一对多 并且书是多的一方 所以外键字段放在书表里面
    """
    publish = models.ForeignKey(to='Publish')  # 默认就是与出版社表的主键字段做外键关联
    """
    如果字段对应的是ForeignKey  那么orm会自动在字段的后面加_id
    如果你自作聪明的加了_id那么orm还是会在后面继续加_id
    
    后面在定义ForeignKey的时候就不要自己加_id
    """


    """
    图书和作者是多对多的关系  外键字段建在任意一方均可  但是推荐你建在查询频率较高的一方
    """
    authors = models.ManyToManyField(to='Author')
    """
    authors是一个虚拟字段  主要是来告诉orm  书籍表和作者是多对多关系
    让orm自动帮你创建第三张关系表
    """

# 出版社表
class Publish(models.Model):
    name = models.CharField(max_length=32)
    addr = models.CharField(max_length=32)

# 作者表
class Author(models.Model):
    name = models.CharField(max_length=32)
    age = models.IntegerField()
    """
    作者与作者详情是一对一的关系  外键字段建在任意一方都可以  但是推荐你建在查询频率较高的表中
    """
    author_detail = models.OneToOneField(to='AuthorDetail')
    """
    OneToOneField也会自动给字段加_id后缀
    所以你也不要自作聪明的自己加_id
    """

# 作者详情表
class AuthorDetail(models.Model):
    phone = models.BigIntegerField()  # 或者直接用字符类型
    addr = models.CharField(max_length=32)
    
    
    
"""
orm中如何定义三种关系
publish = models.ForeignKey(to='Publish')
authors = models.ManyToManyField(to='Author')
author_detail = models.OneToOneField(to='AuthorDetail')

ForeignKey 
OneToOneField
会自动在字段后面加_id后缀
"""

# 在django1.x版本中外键默认都是级联更新删除的
# 多对多的表关系可以有好几种创建方式 这里暂且先介绍一种
# 针对外键字段里面的其他参数 暂时不要考虑 如果感兴趣可以百度先试试看

 

判断表关系的方式:换位思考

"""
一对多
    models.ForeignKey(to='关联表名')  # 常用
    models.ForeignKey(to=关联表名)  # 关联表名必须出现在上方 不加引号的话(了解即可)
        1、在django1.x版本中外键默认就是级联更新删除的
        2、会自动给字段加_id后缀 无论你有没有加(自己不要自作聪明的加上)        
        3、一对多  外键字段建在多的一方


一对一
    models.OneToOneField(to='关联表名')
        1、在django1.x版本中外键默认就是级联更新删除的
        2、会自动给字段加_id后缀 无论你有没有加(自己不要自作聪明的加上)    
        3、外键建在任意一方均可 但是推荐你建在查询频率较高的表中(orm查方便)


多对多
    models.ManyToManyField(to='关联表名')
        1、在django1.x版本中外键默认就是级联更新删除的
        2、该字段是一个虚拟字段不会真正的在表中展示出来 而是用来告诉django orm当前表和关联表是多对多的外键关系 需要自动创建第三张关系表
        3、在django orm中多对多的表关系有好几种(三种)创建方式
        4、外键建在任意一方均可 但是推荐你建在查询频率较高的表中(orm查方便)

判断表关系的方式:换位思考
"""

 

django请求生命周期流程图(必会)

 

 

"""
浏览器
    发送请求(HTTP协议)
    
web服务网关接口
    1、请求来的时候解析封装
       响应走的时候打包处理
    
    2、django默认的wsgiref模块不能承受高并发 最大只有1000左右
       上线之后会替换成uwsgi来增加并发量
      
    3、WSGJ跟wsgiref和uwsgi是什么关系
        WSGI是协议
        wsgiref和uwsgi是实现该协议的功能模块
    
django后端
    1、django中间件(暂时不考虑 后面讲)
        类似于dganjo的保安 门户
    
    2、urls.py  路由层
        识别路由 匹配对应的视图函数
        
    3、views.py  视图层
        网站整体的业务逻辑
    
    4、templates文件夹  模板层
        网站所有的html文件
        
    5、models.py  模型层
        ORM
        
额外拓展:缓存数据库的作用
"""

 

# 扩展知识点
    """
    缓存数据库
        提前已经将你想要得到数据准备好了  你来直接拿就可以
        提高效率和响应时间
    
    当你在修改你的数据的时候 你会发现数据并不是立刻修改完成的
    而是需要经过一段时间才会修改
        博客园
    
    了解即可
    """

 

测试脚本

"""
当你只是想测试django中的某一个py文件内容 那么你可以不用书写前后端交互式的形式
而是直接写一个测试脚本即可

脚本代码无论是写在应用下的test.py还是自己单独开设mytest.py文件都可以
"""

# 测试环境的准备  去manage.py中拷贝前四行代码 然后自己写两行
import os
import sys

if __name__ == "__main__":
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day64.settings")
    import django
    django.setup()
    
    # 在这个代码块的下面就可以测试django里面的单个py文件了
    # 所有的代码都必须等待环境准备完毕之后才能书写
    from app01 import models
    models.User.objects.all()

 

单表操作之内容回顾

# django自带的sqlite3数据库对日期格式不是很敏感 处理的时候容易出错

 

 #
    # res = models.User.objects.create(name='jason',age=18,register_time='2020-1-21')
    
    # create返回值就是当前被创建的数据对象
    # print(res)
    
    # import datetime
    # ctime = datetime.datetime.now()
    # user_obj = models.User(name='egon',age=84,register_time=ctime)
    # user_obj.save()


    #
    # 方式一
    # res = models.User.objects.filter(pk=2).delete()
    # print(res)  # (1, {'app01.User': 1})
    """
    pk会自动查找到当前表的主键字段 指代的就是当前表的主键字段
    用了pk之后 你就不需要知道当前表的主键字段到底是叫什么了
        uid
        pid
        sid...都不需要看了
    """
    # 方式二
    # user_obj = models.User.objects.filter(pk=1).first()
    # user_obj.delete()


    # 修改
    # 方式一
    # models.User.objects.filter(pk=4).update(name='egonDSB')
    # 方式二
    # user_obj = models.User.objects.get(pk=4)
    """
    get方法返回的直接是当前数据对象
    但是该方法不推荐使用
        一旦数据不存在该方法会直接报错
        而filter则不会 会返回空
            所以我们还是用filter
    """
    # user_obj.name='egonPPP'
    # user_obj.save()

 

查看内部sql语句的方式

# 方式一
下列查看sql语句的方式 只能用于QuerySet对象
只有QuerySet对象才能够点击query查看内部的sql语句

res = models.User.objects.values_list('name','age')
print(res)
# <QuerySet [('jason', 18), ('egonPPP', 84)]>
print(res.query)  # 查看内部封装的sql语句
# SELECT `app01_user`.`name`, `app01_user`.`age` FROM `app01_user`



# 方式二:所有的sql语句都能查看
# 去配置文件中配置一下即可
# 详情参见:https://www.cnblogs.com/Dominic-Ji/p/9203990.html

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'console':{
            'level':'DEBUG',
            'class':'logging.StreamHandler',
        },
    },
    'loggers': {
        'django.db.backends': {
            'handlers': ['console'],
            'propagate': True,
            'level':'DEBUG',
        },
    }
}

 

常见的十几种查询方法

 """
 QuerySet对象还支持切片操作 但是只能填正数
 """
    # 必知必会N多条 目前13条
    # 1、all()
    # 2、filter()
    # 3、get()
    # 4、first()
    # 5、last()
    # 6、values()
    # 7、values_list
    # 8、distinct()
    # 9、order_by()
    # 10、reverse()
    # 11、count()
    # 12、exclude()
    # 13、exists()

    # 1、all()  查询所有数据

    # 2、filter()  带有过滤条件的查询

    # 3、get()  直接拿数据对象 但是条件不存在的话直接报错

    # 4、first()  拿queryset里面第一个元素
    # res = models.User.objects.all().first()
    # print(res)

    # 5、last()  拿queryset里面最后一个元素
    # res = models.User.objects.all().last()
    # print(res)

    # 6、values()  # 可以指定获取的数据字段 select name,age from ...  返回结果:可以看成列表套字典
    # res = models.User.objects.values('name','age')
    # print(res)
    # <QuerySet [{'name': 'jason', 'age': 18}, {'name': 'egonPPP', 'age': 84}]>

    # 7、values_list  # 可以看成列表套元组
    # res = models.User.objects.values_list('name','age')
    # print(res)
    # <QuerySet [('jason', 18), ('egonPPP', 84)]>
    # print(res.query)  # 查看内部封装的sql语句
    # SELECT `app01_user`.`name`, `app01_user`.`age` FROM `app01_user`
    """
    上述查看sql语句的方式 只能用于QuerySet对象
    只有QuerySet对象才能够点击query查看内部的sql语句
    """


    # 8、distinct()  去重
    # res = models.User.objects.all().values('name','age').distinct()
    # print(res)
    """
    去重一定要是一模一样的数据
    如果带有主键那么肯定不一样 你在往后的查询中一定不要忽略主键
    """

    # 9、order_by()  排序 默认升序
    # res1 = models.User.objects.order_by('age')  # 默认升序
    # res2 = models.User.objects.order_by('-age')  # 降序  加减号
    # print(res1)
    # print(res2)


    # 10、reverse()  反转的前提是数据已经排序过了  order_by()之后
    # res = models.User.objects.all()
    # res1 = models.User.objects.order_by('age').reverse()
    # print(res)
    # print(res1)




    # 11、count  # 统计当前数据的个数
    # res = models.User.objects.count()
    # print(res)  # 4



    # 12、exclude()  # 排除在外
    # res = models.User.objects.exclude(name='jason')
    # print(res)


    # 13、exists() 判断某个东西是否存在  基本用不到  返回的是布尔值
    # 因为数据本身就自带布尔值
    # res = models.User.objects.filter(pk=0).exists()
    # print(res)

 

神奇的双下划线查询

# 神奇的双下划线查询
    # 1、年龄大于35的数据
    # res = models.User.objects.filter(age__gt=35)
    # print(res)
    # 2、年龄小于35的数据
    # res = models.User.objects.filter(age__lt=35)
    # print(res)
    # 大于等于 小于等于   gt lt后面加e
    # res = models.User.objects.filter(age__gte=32)
    # print(res)
    # res = models.User.objects.filter(age__lte=32)
    # print(res)

    # 年龄是18 或 32 或 40
    # res = models.User.objects.filter(age__in=[18,32,40])
    # print(res)

    # 年龄在18-40岁之间 首尾都要
    # res = models.User.objects.filter(age__range=[18,40])
    # print(res)

    # 查询出名字里面含有n的数据  模糊查询
    # res = models.User.objects.filter(name__contains='n')
    # print(res)
    # 是否区分大小写   查询出名字里面含有p的数据  区分大小写
    # res = models.User.objects.filter(name__contains='p')
    # print(res)
    # 忽略大小写  加i
    # res = models.User.objects.filter(name__icontains='p')
    # print(res)

    # 以j开头
    # res = models.User.objects.filter(name__startswith='j')
    # print(res)
    # 以j结尾
    # res = models.User.objects.filter(name__endswith='j')
    # print(res)


    # 查询出注册时间是 2020 1月
    # res = models.User.objects.filter(register_time__month='1')  # 月
    # res = models.User.objects.filter(register_time__year='2020')  # 年
    # res = models.User.objects.filter(register_time__day='21')  # 日
    # print(res)

 

一对多的外键增删改查

 # 一对多外键增删改查
    #
    # 方式一  直接写实际字段id
    models.Book.objects.create(title='论语',price=869.23,publish_id=1)
    models.Book.objects.create(title='聊斋',price=333.23,publish_id=2)
    models.Book.objects.create(title='老子',price=444.23,publish_id=1)
    # 方式二 虚拟字段 对象
    # publish_obj = models.Publish.objects.filter(pk=2).first()
    # models.Book.objects.create(title='红楼梦',price=666.23,publish=publish_obj)

    #
    # models.Publish.objects.filter(pk=1).delete()  # 级联删除

    #
    # 方式一  直接写实际字段id
    # models.Book.objects.filter(pk=1).update(publish_id=2)
    # 方式二  虚拟字段 对象
    # publish_obj = models.Publish.objects.filter(pk=1).first()
    # models.Book.objects.filter(pk=1).update(publish=publish_obj)

 

多对多外键增删改查

 # 多对多 增删改查 就是在操作第三张表

    #
    # 如何给书籍添加作者???
    # book_obj = models.Book.objects.filter(pk=2).first()
    # print(book_obj.authors)  # 就类似于你已经到了第三张关系表了
    # book_obj.authors.add(1)  # 书籍id为1的数据绑定一个主键为1的作者
    # book_obj.authors.add(2,3)  # 可以绑定多个

    # author_obj = models.Author.objects.filter(pk=1).first()
    # author_obj1 = models.Author.objects.filter(pk=2).first()
    # author_obj2 = models.Author.objects.filter(pk=3).first()
    # book_obj.authors.add(author_obj)
    # book_obj.authors.add(author_obj1,author_obj2)
    """
    add给第三张关系表添加数据
        括号内既可以传数字也可以传对象 并且都支持多个
    """


    # 删  remove
    # book_obj = models.Book.objects.filter(pk=2).first()
    # book_obj.authors.remove(2)
    # book_obj.authors.remove(1,3)

    # author_obj1 = models.Author.objects.filter(pk=1).first()
    # author_obj2 = models.Author.objects.filter(pk=2).first()
    # book_obj.authors.remove(author_obj1, author_obj2)
    """
    括号内既可以传数字也可以传对象 并且都支持多个
    """


    # 修改  set
    # book_obj = models.Book.objects.filter(pk=1).first()
    # book_obj.authors.set([1,2])  # 括号内必须给一个可迭代对象
    # book_obj.authors.set([3,])  # 括号内必须给一个可迭代对象
    #
    # author_obj1 = models.Author.objects.filter(pk=1).first()
    # author_obj2 = models.Author.objects.filter(pk=2).first()
    # book_obj.authors.set([author_obj1,author_obj2])  # 括号内必须给一个可迭代对象
    """
    set 
        括号内必须传一个可迭代对象
        该对象内既可以传数字也可以传对象 并且都支持多个
        
        先删除 后新增
    """


    # 清空  clear
    # 在第三张关系表中清空某个书籍与作者的绑定关系
    book_obj = models.Book.objects.filter(pk=1).first()
    book_obj.authors.clear()
    """
    clear
        括号内不要加如何参数
    """

 

正反向的概念

正向查询按字段

反向查询按表名小写

# 正向
# 反向
    看外键字段在我手上,那么我查你就是正向
    外键字段如果不在我手上,我查你就是反向
    
    book >>> 外键字段在书那儿(正向) >>> publish
    publish >>> 外键字段在书那儿(反向) >>> book
    
    一对一和多对多 正反向的判断也是如此
    

"""
正向查询按字段
反向查询按表名小写
        基于对象
        反向查询的时候
            当你的查询结果可以有多个的时候 就必须加_set.all()
            当你的结果只有一个时候 不需要加_set.all()
"""

多表查询

"""
# 基于对象的跨表查询

    # 1、查询书籍主键为1的出版社
    # book_obj = models.Book.objects.filter(pk=1).first()
    # # 书查出版社 正向
    # res = book_obj.publish
    # print(res)
    # print(res.name)
    # print(res.addr)


    # 2、查询书籍主键为1的作者
    # book_obj = models.Book.objects.filter(pk=2).first()
    # 书查作者  正向
    # res = book_obj.authors  # app01.Author.None
    # res = book_obj.authors.all()  # <QuerySet [<Author: Author object>]>
    # print(res)

    # 3、查询作者jason的电话号码
    # author_obj = models.Author.objects.filter(name='jason').first()
    # res = author_obj.author_detail
    # print(res)
    # print(res.phone)
    # print(res.addr)
    """
    在书写ORM语句的时候跟写sql语句是一样的
    不要企图一次性将orm语句写完 如果比较复杂 就写一点看一点
    
    正向什么时候需要加.all()
        当你的结果可能有多个的时候需要加.all()
        如果是一个则直接拿到数据对象
        book_obj.publish  作者与出版社 只有一个
        book_obj.authors.all()  书对应的作者 有多个
        author_obj.author_detail 作者与作者详情 只有一个
    """

    # 4、查询出版社是东方出版社出版的书
    # publish_obj = models.Publish.objects.filter(name='东方出版社').first()
    # 出版社查书  反向
    # res = publish_obj.book_set.all()
    # print(res)

    # 5、查询作者是jason写过的书
    # author_obj = models.Author.objects.filter(name='jason').first()
    # 作者查书 反向
    # res = author_obj.book_set.all()
    # print(res)

    # 6、查询手机号是110的作者姓名
    # author_detail_obj = models.AuthorDetail.objects.filter(phone=110).first()
    # res = author_detail_obj.author
    # print(res.name)

    """
    基于对象
        反向查询的时候
            当你的查询结果可以有多个的时候 就必须加_set.all()
            当你的结果只有一个时候 不需要加_set.all()
    """
"""

 

子查询(基于对象的跨表查询)

"""
# 基于对象的跨表查询

    # 1、查询书籍主键为1的出版社
    # book_obj = models.Book.objects.filter(pk=1).first()
    # # 书查出版社 正向
    # res = book_obj.publish
    # print(res)
    # print(res.name)
    # print(res.addr)


    # 2、查询书籍主键为1的作者
    # book_obj = models.Book.objects.filter(pk=2).first()
    # 书查作者  正向
    # res = book_obj.authors  # app01.Author.None
    # res = book_obj.authors.all()  # <QuerySet [<Author: Author object>]>
    # print(res)

    # 3、查询作者jason的电话号码
    # author_obj = models.Author.objects.filter(name='jason').first()
    # res = author_obj.author_detail
    # print(res)
    # print(res.phone)
    # print(res.addr)
    """
    在书写ORM语句的时候跟写sql语句是一样的
    不要企图一次性将orm语句写完 如果比较复杂 就写一点看一点
    
    正向什么时候需要加.all()
        当你的结果可能有多个的时候需要加.all()
        如果是一个则直接拿到数据对象
        book_obj.publish  作者与出版社 只有一个
        book_obj.authors.all()  书对应的作者 有多个
        author_obj.author_detail 作者与作者详情 只有一个
    """

    # 4、查询出版社是东方出版社出版的书
    # publish_obj = models.Publish.objects.filter(name='东方出版社').first()
    # 出版社查书  反向
    # res = publish_obj.book_set.all()
    # print(res)

    # 5、查询作者是jason写过的书
    # author_obj = models.Author.objects.filter(name='jason').first()
    # 作者查书 反向
    # res = author_obj.book_set.all()
    # print(res)

    # 6、查询手机号是110的作者姓名
    # author_detail_obj = models.AuthorDetail.objects.filter(phone=110).first()
    # res = author_detail_obj.author
    # print(res.name)

    """
    基于对象
        反向查询的时候
            当你的查询结果可以有多个的时候 就必须加_set.all()
            当你的结果只有一个时候 不需要加_set.all()
    """
"""

 

联表查询(基于双下划线的跨表查询)

"""
# 基于双下划线的跨表查询


    # 1、查询jason的手机号和作者姓名
    # res = models.Author.objects.filter(name='jason').values('author_detail__phone','name')
    # print(res)

    # 反向
    # res = models.AuthorDetail.objects.filter(author__name='jason')  # 拿作者姓名是jason的作者详情
    # res = models.AuthorDetail.objects.filter(author__name='jason').values('phone','author__name')
    # print(res)




    # 2、查询书籍主键为1的出版社名称和书的名称
    # res = models.Book.objects.filter(pk=1).values('title','publish__name')
    # print(res)
    # 反向
    # res = models.Publish.objects.filter(book__id=1).values('name','book__title')
    # print(res)



    # 3、查询书籍主键为2的作者姓名
    # res = models.Book.objects.filter(pk=2).values('authors__name')
    # print(res)
    # 反向
    # res = models.Author.objects.filter(book__id=2).values('name')
    # print(res)

    # 查询书籍主键是1的作者的手机号
    # book author authordetail
    # res = models.Book.objects.filter(pk=1).values('authors__author_detail__phone')
    # print(res)
    """
    你只要掌握了正反向的概念
    以及双下划线
    那么你就可以无限制的跨表
    """

"""

 

聚合查询(聚合函数的使用)aggregate

    # 聚合查询  单独使用聚合函数需要用到:aggregate
    """
    聚合查询通常情况下都是配合分组一起使用的
    只要是跟数据库相关的模块 
        基本上都在django.db.models里面
        如果上述没有那么应该在django.db里面
    """
    from django.db.models import Max,Min,Sum,Count,Avg
    # 1、统计所有书的平均价格
    res = models.Book.objects.aggregate(Avg('price'))
    print(res)  # {'price__avg': 550.896667}
    # 2、上述方法一次性使用
    res = models.Book.objects.aggregate(Max('price'),Min('price'),Sum('price'),Count('pk'),Avg('price'))
    print(res)

 

分组查询

import os

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day53.settings")
if __name__ == '__main__':
    import django

    django.setup()

    from app01 import models

    # 查询每一个出版社id,以及出书平均价格(单表)
    # 原生sql
    # select publish_id,avg(price) from book group by publish_id;
    # orm实现
    '''标准 annotate() 内写聚合函数
    values在前,表示group by 的字段
    values在后,表示取字段
    filter在前,表示where条件
    filter在后,表示having
    '''
    from django.db.models import Avg,Count,Max

    # res = models.Book.objects.all().\
    #     values('publish_id').\
    #     annotate(price_ave=Avg('price')).values('publish_id','price_ave')
    # print(res)

    # 查询出版社id大于1的出版社id,以及出书平均价格
    # res=models.Book.objects.values('publish_id').filter(publish_id__gt=1).annotate(price_ave=Avg('price')).values('publish_id','price_ave')
    # print(res)

    # 查询出版社id大于1的出版社id,以及出书平均价格大于30的
    # res=models.Book.objects.values('publish_id').filter(publish_id__gt=1).annotate(price_ave=Avg('price')).filter(price_ave__gt=60)
.values('publish_id','price_ave')
# print(res) #查询每一个出版社出版的名称和书籍个数(连表) # 联表的话最好以group by的表作为基表 # res=models.Publish.objects.values('nid').annotate(book_count=Count('book__nid')).values('name','book_count') # 简写成,如果基表是group by的表,就可以不写values # res=models.Publish.objects.annotate(book_count=Count('book')).values('name','book_count') # 以book为基表 # res=models.Book.objects.values('publish__nid').annotate(book_count=Count('nid')).values('publish__name','book_count') # print(res) #查询每个作者的名字,以及出版过书籍的最高价格(建议使用分组的表作为基表) # 多对多如果不以分组表作为基表,可能会出数据问题 # res=models.Author.objects.annotate(price_max=Max('book__price')).values('name','price_max') # res=models.Book.objects.values('authors__nid').annotate(price_max=Max('price')).values('authors__name','price_max') # print(res) #查询每一个书籍的名称,以及对应的作者个数 res=models.Book.objects.annotate(count=Count('authors')).values('name','count') print(res) ##统计不止一个作者的图书 ## 统计价格数大于10元,作者的图书 ##统计价格数大于10元,作者个数大于1的图书 res=models.Book.objects.filter(price__gt=10).annotate(count=Count('authors')).filter(count__gt=1).values('name','price','count') print(res)

 

 # 分组查询  annotate
    """
    MySQL分组查询都有哪些特点
        分组之后默认只能获取到分组的依据 组内其他字段都无法直接获取了
            严格模式
                ONLY_FULL_GROUP_BY
                
    """
    from django.db.models import Max, Min, Sum, Count, Avg
    # 1、统计每一本书的作者个数
    # res = models.Book.objects.annotate()  # models后面点什么就是按照什么分组
    # res = models.Book.objects.annotate(authors_num=Count('authors')).values('title','authors_num')
    """
    等价  authors_num使我们自己定义的字段 用来存储统计出来的每本书对应的作者个数
    """
    # res = models.Book.objects.annotate(authors_num=Count('authors__id')).values('title','authors_num')
    # print(res)

    # 2、统计每个出版社买的最便宜的书的价格
    # res = models.Publish.objects.annotate(min_price=Min('book__price')).values('name', 'min_price')
    # print(res)

    # 3、统计不止一个作者的图书
        # 1、先按照图书分组  求每一本书对应的作者个数
        # 2、过滤出不止一个作者的图书
    # res = models.Book.objects.annotate(author_num=Count('authors')).filter(author_num__gt=1).values('title','author_num')
    # """
    # 只要你的orm语句得出的结果还是一个queryset对象
    # 那么它就可以继续无限制的点queryset对象封装的方法
    # """
    # print(res)


    # 4、查询每个作者出的书的总价格
    # res = models.Author.objects.annotate(sum_price=Sum('book__price')).values('name','sum_price')
    # print(res)

    """
    如果我想按照指定的字段分组该如何处理呢?
        models.Book.object.values('price').annotate()
        后续BBS会使用
    
    如果出现分组查询报错的情况
        你需要修改数据库严格模式    
    """

 

F与Q查询

F查询

# F查询
# F查询做的是取值的操作
    # 1、查询卖出数大于库存数的书籍
    # F查询
    """
    能够帮助你直接获取到表中某个字段对应的数据
    """
    # from django.db.models import F
    # res = models.Book.objects.filter(maichu__gt=F('kucun'))
    # """
    # F会自动拿出每一本书库存字段对应的值 一本一本的进行比较
    # """
    # print(res)


    # 2、将所有书籍的价格提升五十块
    # from django.db.models import F
    # models.Book.objects.update(price=F('price')+50)

    # 3、将所有书的名称后年加上爆款两个字
    """
    在操作字符类型的数据的时候 F不能够直接做到字符串的拼接
    """
    from django.db.models import F
    from django.db.models.functions import Concat
    from django.db.models import Value
    models.Book.objects.update(title=Concat(F('title'),Value('爆款')))
    models.Book.objects.update(title=F('title') + '爆款')  # 所有的名称都会全部变成空白
    
    

 

Q查询

 # Q查询
 # Q查询支持的逻辑运算符(与或非).
    # 1、查询卖出数大于100或者价格小于600的书籍
    # res = models.Book.objects.filter(maichu__gt=100,price__lt=600)
    """filter括号内多个参数是and关系"""
    # print(res)

    from django.db.models import Q
    # res = models.Book.objects.filter(Q(maichu__gt=100),Q(price__lt=600))  # Q包裹逗号分割 还是and关系
    # res = models.Book.objects.filter(Q(maichu__gt=100) | Q(price__lt=600))  # | 就是or关系
    # res = models.Book.objects.filter(~Q(maichu__gt=100) ~ Q(price__lt=600))    # ~ 就是not关系
    # print(res)

    # Q的高阶用法  能够将查询条件的左边也变成字符串的形式
    # q = Q()
    # q.connector = 'or'  # 修改连接关系为or
    # q.children.append(('maichu__gt',100))
    # q.children.append(('price__lt',600))
    # res = models.Book.objects.filter(q)  # filter括号内也支持直接放q对象 默认还是and关系
    # print(res)  

 

django中如何开启事务

"""
事务
    ACID四个特性
    原子性 
        不可分割的最小单位
    一致性 
        跟原子性是相辅相成    
    隔离性 
        事务之间互相不干扰
    持久性
        事务一旦确认永久生效
        
    事务的回滚
        rollback
    事务的确认
        commit
"""

# 目前你只需要掌握django中如何简单的开启事务
        # 事务
    from django.db import transaction
    try:
        with transaction.atomic():
            # sql1
            # sql2
            # ...
            # 在with代码块内书写的所有orm操作都是属于同一个事务
    except Exception as e:
        print(e)
    print('执行其他操作')

 

orm常用字段及参数

详情参见:https://www.cnblogs.com/Dominic-Ji/p/9203990.html

AutoField
    主键字段 primary_key=True
    
CharField        对应到数据库:varchar
    verbose_name 字段的注释
    max_length  字符的长度

IntegerField      对应到数据库:int
BigIntegerField               bigint
    
DecimalField
    max_digits=8
    decimal_places=2
"""
固定精度的十进制数
    max_digits 数中允许的最大数目的数字
    decimal_places 存储小数位数
"""

EmailField     varchar(254)

DateField        date
DateTimeField        datetime
    auto_now:每次修改数据的时候都会自动更新当前时间
    auto_now_add:只在创建数据的时候记录创建时间 后续不会自动修改了
        
        
BooleanField(Field)            - 布尔值类型
    该字段传布尔值(False/True) 数据库里面存0或1
    

 TextField(Field)            - 文本类型
    该字段可以用来存大段内容(文章 博客...) 没有字数限制
    后面BBS作业 文章字段用的就是TextField
    
    
FileField(Field)            - 字符类型
    upload_to = "/data"   
    # 给该字段传一个文件对象 会自动将文件保存到/data目录下然后将文件路径保存到数据库中
    /data/a.txt
    后面BBS也会涉及

    
# 更多字段
直接参考博客:https://www.cnblogs.com/Dominic-Ji/p/9203990.html
    
    
    
# django除了给你提供了很多字段之外 还支持你自定义字段
class MyCharField(models.Field):
    def __init__(self,max_length,*agrs,**kwargs):
        self.max_length = max_length
        # 调用父类的init方法
        super().__init__(max_length=max_length,*agrs,**kwargs)
        # 一定要是关键字的形式传入

    def db_type(self, connection):
        """
        返回真正的数据类型以及各种约束条件
        :param connection:
        :return:
        """
        return 'char(%s)' %self.max_length
    
# 自定义字段使用
    myfield = MyCharField(max_length=16,null=True)
    
    
# 外键字段及参数
unique=True
如果设置为unique=True 则该字段在此表中必须是唯一的 。
    ForeignKey(unique=True)   等价于   OneToOneField()
    # 在用前面的字段创建一对一 orm会有一个提示信息 orm推荐你使用后者 但是前者也能用
    
    
db_index
    如果db_index=True 则代表着为此字段设置索引。
    复习索引是什么
    
    
to_field
设置要关联的表的字段  默认不写关联的就是另外一张的主键字段


on_delete
当删除关联表中的数据时,当前表与其关联的行的行为。
"""
django2.x版本及以上  需要你自己指定外键字段的级联更新,级联删除
django1.x不需要
"""

 

数据库查询优化

only与defer

"""
orm语句特点:
    惰性查询
        如果你仅仅只是书写了orm语句 在后面根本没有用到该语句所查询出来的参数
        那么orm会自动识别 直接不执行
    # res  = models.Book.objects.all()
    # print(res)  # 要用数据了才会走数据库
"""

# only与defer
# only
    # res  = models.Book.objects.all()
    # print(res)  # 要用数据了才会走数据库

    # 想要获取书籍表中所有书的名字
    # res = models.Book.objects.values('title')
    # for d in res:
    #     print(d.get('title'))
    # 实现获取到的是一个数据对象 然后点title就能够拿到书名 并且没有其他字段
    # res = models.Book.objects.only('title')
    # res = models.Book.objects.all()
    # print(res)
    # for i in res:
    #     print(i.title)  # 点击only括号内的字段 不会走数据库
        # print(i.price)  # 点击only括号内没有的字段 会重新走数据库查询而all不需要

        
# defer
    # res = models.Book.objects.defer('title')  # 对象除了没有title 其他属性都有
    # for i in res:
    #     print(i.price)

    """
    defer与only刚好相反
        defer括号内放的字段不在查询出来的对象里面 查询该字段需要重新走数据库
        而如果查询的是非括号内的字段 则不需要走数据库了
    """
    
    
    
    
    

 

select_related与prefetch_related

 # select_related与prefetch_related  跟跨表操作有关
    # res = models.Book.objects.all()
    # for i in res:
    #     print(i.publish.name)  # 每循环一次就要走一次数据库查询

    # res = models.Book.objects.select_related('publish')  # INNER JOIN 联表查询  查一次
    
    """
    select_related内部直接先将book与publish连起来 然后一次性将大表里面的所有数据
    全部封装给查询出来的对象
        这个时候对象无论是点击book表还是publish的数据都无需再走数据库查询了
        
    select_related括号内只能放外键字段  一对多 一对一
        多对多不行
    """
    
    # for i in res:
    #     print(i.publish.name)  # 每循环一次就要走一次数据库查询


    res = models.Book.objects.prefetch_related('publish')  # 子查询  查两次
    """
    prefetch_related该方法内部其实就是子查询
        将子查询查询出来的所有结果也给你封装到对象中
        给你的感觉好像也是一次性搞定的
    """
    for i in res:
        print(i.publish.name)

 

图书管理的图书增删改查

from django.shortcuts import render,redirect,HttpResponse
from app01 import  models

# Create your views here.

# 首页
def home(request):
    return render(request,'home.html')


# 图书的展示页
def book_list(request):
    # 先查询出所有的书籍信息 传递给html页面
    book_queryset = models.Book.objects.all()
    return render(request,'book_list.html',locals())

# 图书的添加
def book_add(request):
    if request.method == 'POST':
        # 获取前端提交过来的所有数据
        title = request.POST.get('title')
        price = request.POST.get('price')
        publish_date = request.POST.get('publish_date')
        publish_id = request.POST.get('publish')
        authors_list = request.POST.getlist('authors')  # [1,2,3,4]

        # 操作数据库存储数据
        # 书籍表
        book_obj = models.Book.objects.create(title=title,price=price,publish_date=publish_date,publish_id=publish_id)


        # 书籍与作者的关系表
        book_obj.authors.add(*authors_list)
        # 跳转到书籍的展示页面
        """
        redirect括号内可以直接写url
        其实也可以直接写别名
        
        但是如果你的别名需要额外给参数的话 那么就必须使用reverse解析了
        """
        return redirect('book_list')
    # 先获取当前系统中所有的出版社信息和作者信息
    publish_queryset = models.Publish.objects.all()
    author_queryset = models.Author.objects.all()

    return render(request,'book_add.html',locals())

# 编辑
def book_edit(request,edit_id):
    # 获取当前用户想要编辑的书籍对象 展示给用户看
    edit_obj = models.Book.objects.filter(pk=edit_id).first()

    if request.method == 'POST':
        # 获取前端提交过来的所有数据
        title = request.POST.get('title')
        price = request.POST.get('price')
        publish_date = request.POST.get('publish_date')
        publish_id = request.POST.get('publish')
        authors_list = request.POST.getlist('authors')  # [1,2,3,4]
        models.Book.objects.filter(pk=edit_id).update(title=title,price=price,publish_date=publish_date,publish_id=publish_id)

        # 改第三种关系表
        edit_obj.authors.set(authors_list)
        return redirect('book_list')



    publish_queryset = models.Publish.objects.all()
    author_queryset = models.Author.objects.all()

    return render(request,'book_edit.html',locals())

# 删除
def book_delete(request,delete_id):
    # 简单粗暴直接删除
    models.Book.objects.filter(pk=delete_id).delete()
    # 直接跳转到展示页
    return redirect('book_list')

 

choice参数(数据库字段设计常见)

"""
用户表
    性别
    学历
    工作经验
    是否结婚
    是否生子
    客户来源
    ...
针对某个可以列举完全的可能性字段,我们应该如何存储


只要某个字段的可能性是可以列举完全的 那么一般情况下都会采用choices参数
"""

class User(models.Model):
    username = models.CharField(max_length=32)
    age = models.IntegerField()
    # 性别
    gender_choice = (
        (1,''),
        (2,''),
        (3,'其他'),
    )
    gender = models.IntegerField(choices=gender_choice)

    score_choices = (
        ('A','优秀'),
        ('B','良好'),
        ('C','及格'),
        ('D','不合格'),
    )
    # 保证字段类型跟列举出来的元组第一个数据类型一致即可
    score = models.CharField(choices=score_choices,null=True)

    """
    该gender字段存的还是数字 但是如果存的数字在上面元组列举的范围之内
    那么可以非常轻松的获取到数字对应的真正的内容
    
    1、gender字段存的数字不在上述元组列举的范围内容
    2、如果在 如何获取对应的中文信息
    """
    
    
test.py
from django.test import TestCase

# Create your tests here.
#!/usr/bin/env python
import os
import sys

if __name__ == "__main__":
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day66.settings")
    import django
    django.setup()

    #
    from app01 import models
    # models.User.objects.create(username='jason',age=18,gender=1)
    # models.User.objects.create(username='egon',age=85,gender=2)
    # models.User.objects.create(username='tank',age=40,gender=3)
    # # 存的时候 没有列举出来的数字也能存(范围还是按照字段类型决定的)
    # models.User.objects.create(username='tony',age=45,gender=4)

    #
    # user_obj = models.User.objects.filter(pk=1).first()
    # print(user_obj.gender)
    # 只要是choices参数的字段 如果你想要获取对应信息 固定写法 get_字段名_display()
    # print(user_obj.get_gender_display())  # 男

    # user_obj = models.User.objects.filter(pk=4).first()
    # 如果没有对应关系 那么字段是什么还是展示什么
    # print(user_obj.get_gender_display())  # 4


    
# 实际项目案例
详情参见:https://cnblogs.com/Dominic-Ji/p/10580579.html
    
"""
choices参数使用场景是非常广泛的
"""

 

MTV与MVC模型

# MTV:Django号称是MTV模型
M:models
T:templates
V:views

# MVC:其实Django本质也是MVC
M:models
V:views
C:controller
    
# vue框架:MVVM

 

多对多三种创建方式(中介模型)

# 全自动:利用orm自动帮我们创建第三张关系表
class Book(models.Model):
    name = models.CharField(max_length=32)
    authors = models.ManyToManyField(to='Author')

class Author(models.Model):
    name = models.CharField(max_length=32)
"""
优点:代码不需要自己写 非常方便 还支持orm提供的操作第三张关系表的方法add,remocve,clear...

不足之处:第三张关系表的拓展性极差(没有办法额外的添加字段)
"""


# 纯手动:
class Book(models.Model):
    name = models.CharField(max_length=32)

class Author(models.Model):
    name = models.CharField(max_length=32)
   
class Book2Author(models.Model):
    book_id = models.ForeignKey(to='Book')
    author_id = models.ForeignKey(to='Author')
"""
优点:第三张表完全取决于你自己进行额外的拓展
不足之处:需要写的代码较多 不能够在使用orm提供的简单的方法
不建议用该方式
"""



# 半自动
class Book(models.Model):
    name = models.CharField(max_length=32)
    authors = models.ManyToManyField(to='Author',
                                     through='Book2Author',
                                     through_fields=('book','author')
                                     )

class Author(models.Model):
    name = models.CharField(max_length=32)
    # books = models.ManyToManyField(to='Book',
    #                                  through='Book2Author',
    #                                  through_fields=('author','book')
    #                                  )

class Book2Author(models.Model):
    book = models.ForeignKey(to='Book')
    author = models.ForeignKey(to='Author')

"""
through:手动创建第三张表,指定通过哪个表
through_fields:关联字段是什么

through_fields字段先后顺序
    判断的本质:
        通过第三张表查询对应的表 需用到哪个字段就把哪个字段放前面
    你也可以简化判断
        当前表是谁 就把对应的关联字段放前面
"""
"""
半自动:可以使用orm的正反向查询 但是没法使用add,set,remove,clear这四个方法
       原来的多对多操作api用不了了 需要手动操作
"""

# 总结:
    需要掌握的是半自动和全自动  为了拓展性更高 一般都会采用半自动(写代码要给自己留一条后路)

 

Meta元信息

详情参见:
    http://liuqingzheng.top/python/Django%E6%A1%86%E6%9E%B6/10-%E6%A8%A1%E5%9E%8B%E5%B1%82-%E5%B8%B8%E7%94%A8%E9%9D%9E%E5%B8%B8%E7%94%A8%E5%AD%97%E6%AE%B5%E5%92%8C%E5%8F%82%E6%95%B0/#2-ORM%E5%AD%97%E6%AE%B5%E5%8F%82%E6%95%B0
    
"""
在每一个模型类中都可以写

ORM对应的类里面包含另一个Meta类,而Meta类封装了一些数据库的信息。主要字段如下:

db_table
ORM在数据库中的表名默认是 app_类名,可以通过db_table可以重写表名。

index_together
联合索引。

unique_together
联合唯一索引。

ordering
指定默认按什么字段排序。

只有设置了该属性,我们查询到的结果才可以被reverse()。
"""   

 

原生sql

详情参见:
    http://liuqingzheng.top/python/Django%E6%A1%86%E6%9E%B6/11-%E6%A8%A1%E5%9E%8B%E5%B1%82-%E6%A8%A1%E5%9E%8B%E5%B1%82%E8%BF%9B%E9%98%B6/
        
        
from django.db import connection, connections

cursor = connection.cursor() # connection=default数据
cursor = connections['db2'].cursor()

cursor.execute("""SELECT * from auth_user where id = %s""", [1])

row = cursor.fetchone()
row = cursor.fetchall()

ret = models.Author.objects.raw('select * from app01_author where nid>1')
print(ret)
for i in ret:
    print(i)
print(ret.query)
# 会把book的字段放到author对象中
ret = models.Author.objects.raw('select * from app01_book where nid>1')
print(ret)
for i in ret:
    print(i.price)
    print(type(i))
    
# 执行原生sql 跟对象类型无关了 查出什么字段  可以直接使用该字段

 批量插入数据

# 批量加入数据
def ab_pl(request):
    # # 先给Book表插入一万条数据
    # for i in range(1000):
    #     models.Book.objects.create(title='第%s本书' % i)
    # # 再将所有的数据查询并展示到前端页面
    # book_queryset = models.Book.objects.all()

    # 批量插入
    book_list = []
    for i in range(100000):
        book_obj = models.Book(title='第%s本书' % i)
        book_list.append(book_obj)
    models.Book.objects.bulk_create(book_list)
    # 再将所有的数据查询并展示到前端页面
    book_queryset = models.Book.objects.all()
    """
    当你想要批量插入数据的时候 使用orm给你提供的bulk_create能够大大的减少操作时间
    """

    return render(request,'ab_pl.html',locals())

 

posted @ 2021-06-10 21:30  Palpitate~  阅读(35)  评论(0编辑  收藏  举报