Django中ORM的具体使用,超全超长超好懂

一、django字段和字段参数介绍

class Book(models.Model):
    # 如果不写id,会默认一个id,并且自增
    #primary_key=True  表示该字段是主键,一个表中只能由一个主键
    # id = models.AutoField(primary_key=True)
    # varchar类型,长度,
    # 字段是否可以为空:null=True,可以为空
    # 默认值:default='未知书名',如果没传,默认是它
    # 设置索引:db_index=True 表示该字段是辅助索引
    # 是否唯一:unique=True 表示唯一
    name=models.CharField(max_length=32,null=True,default='未知书名',db_index=True,unique=True)
    # float类型
    # max_digits 最大长度是5  4567.5
    # decimal_places=2 小数点后两位   23.56     999.99
    price=models.DecimalField(max_digits=5,decimal_places=2)

    # DateTimeField年月日时分秒
    # auto_now=True  修改,默认使用当前时间
    # auto_now_add=True 新增,设置当前时间
    publish_date=models.DateTimeField(auto_now=True)

    publish=models.CharField(max_length=32)

二、单表查询

# 查询名字叫xxx的书

from app01 import models
def books(request):
    # models.Book.objects.create(name='xxx',price=10.34,publish='南京出版社')
    #
    #
    # book=models.Book(name='yyy',price=11.34,publish='南京出版社')
    # book.save()

    # 查询所有
    res=models.Book.objects.all()
    print(res)
    # 查询名字叫xxx的书(是个列表:QuerySet)
    res = models.Book.objects.filter(name='xxx')
    res = models.Book.objects.filter(name='xxx')[0]
    res = models.Book.objects.filter(name='xxx').first()

    # 查询名字叫xxx的书(就是book对象),如果没有或者由多个,都报错
    # 查询结果必须有且仅有一个才正常,否则报错
    res=models.Book.objects.get(name='sss')

    # 

    print(res.name)
    return HttpResponse('两本书保存成功')

三、常用字段和非常用字段和参数简介

  常用字段
	-IntegerField   整数
    -AutoField
    -BooleanField
    -CharField
    -DateField
    -DateTimeField
    -DecimalField(max_digits=5, decimal_places=2)
    -FileField   上传文件,本质是varchar
    -ImageField   图片,本质是varchar,继承了FileField
    -TextField   存大文本
    -EmailField   本质是varchar
  非常用字段
	-BigAutoField
    -SmallIntegerField   
    -PositiveSmallIntegerField
    -PositiveIntegerField
    -BigIntegerField
    
    
            'AutoField': 'integer AUTO_INCREMENT',
            'BigAutoField': 'bigint AUTO_INCREMENT',
            'BinaryField': 'longblob',
            'BooleanField': 'bool',
            'CharField': 'varchar(%(max_length)s)',
            'CommaSeparatedIntegerField': 'varchar(%(max_length)s)',
            'DateField': 'date',
            'DateTimeField': 'datetime',
            'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)',
            'DurationField': 'bigint',
            'FileField': 'varchar(%(max_length)s)',
            'FilePathField': 'varchar(%(max_length)s)',
            'FloatField': 'double precision',
            'IntegerField': 'integer',
            'BigIntegerField': 'bigint',
            'IPAddressField': 'char(15)',
            'GenericIPAddressField': 'char(39)',
            'NullBooleanField': 'bool',
            'OneToOneField': 'integer',
            'PositiveIntegerField': 'integer UNSIGNED',
            'PositiveSmallIntegerField': 'smallint UNSIGNED',
            'SlugField': 'varchar(%(max_length)s)',
            'SmallIntegerField': 'smallint',
            'TextField': 'longtext',
            'TimeField': 'time',
            'UUIDField': 'char(32)',
                
  常用参数
	-null
    -max_length
    -default
    -primary_key
    -unique
    -db_index
    
      
    -choices:比较常用(后面再说)
	-blank: django admin里提交数据,限制
        
  元数据
	-必须记住的
    class Meta:
        #  数据库中显示的表名
        db_table = "book"
        #  联合索引
        index_together = [
            ("name", "publish"),
        ]
        #  联合唯一
        unique_together = (("name", "publish"),)
        
   -了解

	    #  admin中显示的表名称
    
        verbose_name='图书表'
        #verbose_name加s
        verbose_name_plural='图书表'
        

class Book(models.Model):
    id=models.AutoField(primary_key=True)
    name=models.CharField(max_length=32)
      时区相关
      默认存当前时间,默认存utc时间
      咱们是东八区,存到数据库中时间差8个小时
      通过设置,让存的时候,就存东八区时间,在配置文件中
    publish_date=models.DateTimeField(auto_now_add=True)
      blank=True 在admin中新增数据,可以为空
      修改跟数据库有关才需要做迁移
    publish=models.CharField(max_length=32,null=True,blank=True)
    class Meta:
          表名
        db_table = "book"
            联合索引
        index_together = [
            ("name", "publish"),
        ]
          联合唯一
          unique_together = (("name", "publish"),)

          admin中显示的表名称
        verbose_name='图书表'
        #verbose_name加s
        verbose_name_plural='图书表'

        
        
       
#  自定义字段
class MyCharField(models.Field):
    def __init__(self, max_length, *args, **kwargs):
        self.max_length = max_length
        super().__init(max_length=max_length, *args, **kwargs)
        
    def db_type(self, connection):
        return 'char(%s)' % self.max_length 

五、打印原生SQL配置

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

六、查询表记录API

<1> all():                  查询所有结果
<2> filter(**kwargs):       它包含了与所给筛选条件相匹配的对象
<3> get(**kwargs):          返回与所给筛选条件相匹配的对象,返回结果有且只有一个,如果符合筛选条件的对象超过一个或者没有都会抛出错误。
<4> exclude(**kwargs):      它包含了与所给筛选条件不匹配的对象
<5> order_by(*field):       对查询结果排序('-id')
<6> reverse():              对查询结果反向排序
<8> count():                返回数据库中匹配查询(QuerySet)的对象数量。
<9> first():                返回第一条记录
<10> last():                返回最后一条记录
<11> exists():              如果QuerySet包含数据,就返回True,否则返回False
    
<12> values(*field):        
    返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的并不是一系列models的实例化对象,而是一个可迭代的字典序列
    
<13> values_list(*field):   它与values()非常相似,它返回的是一个元组序列,values返回的是一个字典序列
    
<14> distinct():            从返回结果中剔除重复纪录


      ##  单表api操作
      # 1 all 查询所有,返回queryset对象,目前先当成列表(像列表)
      res=models.Book.objects.all()
      print(res)
      from django.db.models.query import QuerySet
      print(type(res))

      # 2 filter 过滤 queryset对象的方法
      res=models.Book.objects.filter(name='红楼梦')
      print(res)
      res=models.Book.objects.all().filter(name='红楼梦')
      print(res)
      res = models.Book.objects.all().filter(name='红楼梦',publish='东京出版社')
      print(res)
      print(type(models.Book.objects))   暂时不用管

      #  # 3 get  queryset对象的方法
      res = models.Book.objects.all().get(name='红楼梦')
      res = models.Book.objects.get(name='红楼梦')
      res = models.Book.objects.filter().get(name='红楼梦')

      # 4  exclude  排除 ,返回queryset对象,可以继续链式调用
      查询名字不是红楼梦的数据
      res=models.Book.objects.exclude(name='红楼梦')
      print(res)

      # 5 order_by  排序(先后,由顺序)  加-表示降序
      res=models.Book.objects.all().order_by('id')
      res=models.Book.objects.all().order_by('-id')
      res=models.Book.objects.all().order_by('name','-id',)
      res=models.Book.objects.all().order_by('-id','name')
      print(res)

      # 6 reverse 反向 ,必须结合order_by使用,对结果进行反转
      等同于 ('-i')
      res = models.Book.objects.exclude(name='红楼梦').order_by('id')
        res = models.Book.objects.exclude(name='红楼梦').order_by('id').reverse()
      print(res)

      # 7 count  统计条数
      res=models.Book.objects.exclude(name='红楼梦').count()
      res=models.Book.objects.all().count()
      print(res)

      # 9 first  返回结果不再是queryset对象了
      res = models.Book.objects.exclude(name='红楼梦').first()
      print(res)
      # 10 last  返回结果不再是queryset对象了
      res = models.Book.objects.exclude(name='红楼梦').last()
      print(res)

      # 11  exists() 判断结果有没有值 返回结果不再是queryset对象了
      res = models.Book.objects.exclude(name='红楼梦').exists()
      print(res)
      res = models.Book.objects.filter(name='红楼梦dasf').exists()
      print(res)

      # 12 values  select name from book; 指定只查某几个字段

      res = models.Book.objects.all().values('name','publish')
      res = models.Book.objects.all().values('name','publish').first()
     
      print(type(res))

      # 13 values_list
      res = models.Book.objects.all().values_list('name','publish').first()
      print(res)
      print(type(res))

      # 14 distinct 对结果进行去重
      res = models.Book.objects.all().values('name','publish').distinct()
      res = models.Book.objects.all().values('name').distinct()
      print(res)

    
    res.query()  # 查看内部封装的sql语句,前提是对象时queryset对象

七、基于双下划线的模糊查询

  # 1  价格在[100,200,300]这个范围内
Book.objects.filter(price__in=[100,200,300])
  # 2 大于,小于,大于等于,小于等于
Book.objects.filter(price__gt=100)
Book.objects.filter(price__lt=100)
Book.objects.filter(price__gte=100)
Book.objects.filter(price__lte=100)
  # 3 范围
Book.objects.filter(price__range=[100,200])
  # 4 包含
Book.objects.filter(title__contains="python")
  # 5 忽略大小写包含
Book.objects.filter(title__icontains="python")
  # 6 以xx开头
Book.objects.filter(title__startswith="py")
  # 7 时间类型,年份是2012年的
Book.objects.filter(pub_date__year=2012)

八、删除、修改表记录

删除的两种方式
      第一种:queryset的delete方法
    res=models.Book.objects.all().delete()
    print(res)
      第二种:对象自己的delete方法
    book = models.Book.objects.all().filter(name='红楼梦').first()
    print(type(book))
    res=book.delete()
    修改记录
      第一种:queryset的update方法
    res=models.Book.objects.filter(publish='东京').update(name='红楼梦1')
    print(res)
      第二种:对象自己的
    book = models.Book.objects.filter(name='xxx').last()
    book.name='红楼梦1'
    book.save()

九、在Django中使用测试模式

# 新建一个test.py
import os
if __name__ == '__main__':
     1  引入django配置文件
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'day67.settings')
      2 让djagno启动
    import django
    django.setup()
      3 使用表模型
    from app01 import models
    models.Book.objects.create(name='测试书籍',publish='xx出版社')

十、时区和国际化

setting.py中
1 后台管理汉语问题
	LANGUAGE_CODE = 'zh-hans'    管理后台看到的就是中文
2 时区问题(使用东八区)
	TIME_ZONE = 'Asia/Shanghai'
    USE_TZ = False

十一、Django后台管理账号的创建

0 管理后台是django提供的可以快速对表进行增删查改操作

1 创建一个后台管理账号
    python3 manage.py createsuperuser
    输入用户名
    输入邮箱(可以不填,敲回车)
    输入密码
    确认密码
      超级用户创建出来了,可以登录管理后台了
2 admin中表中一行一行的数据显示我们定制的样子(************)
	重写模型类的__str__方法

3 blank参数作用
1 需要把book表注册到admin中
	在app下的admin.py中写
    from app01 import models
	  把book表注册,管理后台就能看到了
	admin.site.register(models.Book)
2 可以快速的对book表进行增删查改操作	

3、blank=True  # 在admin中可以允许插入空值

十二、多表创建之模型创建

1 图书表:book,作者表:author,作者详情表:authordetail,出版社表:publish,(第三张中间表)
2 作者跟作者详情:是一对一,关联字段写在哪一方都可以
3 图书跟出版社:是一对多,一对多关系一旦确立,关联字段写在多的一方
4 图书和作者:是多对多,多对多的关系需要建立第三张表(可以自动生成)

5 models.py中把关系建立出来
from django.db import models
### django:  
# Create your models here.
class Publish(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32)
    addr = models.CharField(max_length=64)
    phone = models.CharField(max_length=64)
    email = models.EmailField()



class AuthorDetail(models.Model):
    id = models.AutoField(primary_key=True)
    sex = models.SmallIntegerField()
    addr = models.CharField(max_length=64)
    phone = models.BigIntegerField()


class Author(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32)
    age = models.SmallIntegerField()
    # 一对一的本质是  ForeignKey+unique
    author_detail=models.OneToOneField(to='AuthorDetail',to_field='id')
    # author_detail=models.ForeignKey(to='AuthorDetail',to_field='id',unique=True)


class Book(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=6, decimal_places=2)
    publish_date = models.DateTimeField(auto_now_add=True)

    # to='Publish'跟Publish表做关联(ForeignKey,一对多)
    # to_field='id'跟哪个字段做关联
    # publish=models.CharField(max_length=32)
    # publish=models.ForeignKey(to='Publish',to_field='id')  # 写,跟id做关联
    # publish = models.ForeignKey(to='Publish')  # 不写,默认跟主键做关联
    publish = models.ForeignKey(to=Publish)  

    # 自动创建出第三张表(这句话会自动创建第三章表)
    # authors在数据库中不存在该字段,没有to_field
    # 默认情况:第三张表有id字段,当前Book表的id和Author表的id字段
    authors=models.ManyToManyField(to='Author')    

6 同步到mysql数据库
	-配置文件
    -pymysql.install_as_mysqldb()
		-公司可以用过的mysqlclient
    -两条迁移命令:
    	makemigrations
        migrate
    

十三、一对多添加记录

	 # 新增红楼梦图书
publish=models.Publish.objects.create(name='北京出版社',addr='北京',phone='0536-12345678',email='邮箱地址')
    # 新增红楼梦图书
book=models.Book.objects.create(name='红楼梦',price='23.45',publish=publish)# publish=对象
    # book=models.Book.objects.create(name='西游记',price='23.55',publish_id=1)# publish_id=数字
    # 新增西游记
book=models.Book.objects.create(name='西游记',price='23.55',publish_id=publish.id)# publish_id=数字


# 总结:
	1 email可以不传email,本质就是varchar(admin中会判断)
    2 新增图书一段多字段的创建:
    	-publish=publish
        -publish_id=publish.id
    3 写在表模型中的publish字段,到数据库中会变成publish_id(ForeignKey)
    4 查到book对象以后
    	-book.publish     对象
    	-book.publish_id  id号,数字

十四、 多对多添加记录,修改,删除

1 自动创建的表,表模型就拿不到,book.authors代指表模型,无法直接在创建书的时候直接创建


    # 多对多,作者和书
    # 给西游记这本书新增两个作者wu和 xi
    # 去到西游记这本书
    book=models.Book.objects.get(name='西游记')
    
    wu=models.Author.objects.get(id=2)
     xi=models.Author.objects.get(id=3)
    
    # 代指中间表book.authors
    book.authors.add(2,3) # 新增作者,通过id新增
    # # book.authors.add(wu, xi) # 新增作者,通过对象新增
    # book.authors.add(2, xi) # 新增作者,通过对象新增

    # 西游记删除一个作者
    book = models.Book.objects.get(name='西游记')
    book.authors.remove(2)
     xi = models.Author.objects.get(id=3)
    book.authors.remove( xi)  # 已经取到了作者对象

    # clear 清空所有作者
    book = models.Book.objects.get(name='西游记')
    book.authors.add(2, 3)
    book.authors.clear()

    # set 先清空,再add,前提是不存在的作者,必须放在列表里
    book.authors.set([4, ])
    
    # add ,remove,set clear

十五、基于对象的跨表查询(正向反向)

# 跨表查询有两种方式
	-基于对象的跨表查询:子查询
    -基于双下划线的跨表查询:关联查询,连表查询
    
    
# 基于对象的跨表查询
	-查询主键为1的书籍的出版社所在的城市
    
    # 基于对象的跨表查询(子查询)
    # 一对多
    # 查询主键为1的书籍的出版社所在的城市
    book=models.Book.objects.get(id=1) # 第一次查询
    book=models.Book.objects.filter(id=1).first()
    publish=book.publish  # 内部又执行了一次查询,根据publish_id查询publish
    print(publish.addr)

    # 北京出版社出版的所有书籍
    publish=models.Publish.objects.get(name='北京出版社')  # 第一次查询了出版社
    books=publish.book_set.all()    # 表名小写_set     # 第二次,根据出版社id,查询所有书
    print(books)

    """
    正向查询:book表内有publish字段 直接对象.字段名
    反向查询:publish表内没有book字段,出版社对象.表名小写_set.all()
    """
   

    ### 一对一
    # 查询所有住址在山东的作者的姓名
    # 反向查询:author_detail没有author字段,author_detail.表名小写
    author_detail=models.AuthorDetail.objects.filter(addr__contains='山东').first()
    # # 反向
    print(author_detail.author.name)

    # 查询 xi作者的地址
    # 正向
    author=models.Author.objects.get(name=' xi')
    print(author.author_detail.addr)


    # 多对多关系查询
    #红楼梦所有作者的名字以及手机号
    book=models.Book.objects.get(name='红楼梦')
    # # 正向
    authors=book.authors.all()
    for author in authors:
        print(author.name)
        print(author.author_detail.phone)

    # 反向 查询 xi出过的所有书籍的名字
     xi=models.Author.objects.get(name=' xi')
    books=egon.book_set.all()
    for book in books:
        print(book.name)
  

十六、基于双下划线的跨表查询

# 连表查询
   基于对象的跨表查询,先查对象,通过对象再去查另一个对象(正向:字段名,反向:表名小写/表名小写_set.all()# 地址为山东的作者写的所有书
    author_detail=models.AuthorDetail.objects.get(addr='山东')
    author=author_detail.author
    books=author.book_set.all()
    print(books[0].name)

   --(作业)地址为山东的作者写的所有书的出版社名字
	author_detail = models.AuthorDetail.objects.get(addr = '山东')
    author=author_detail.author
    books = author.book_set.all()
    for book in books:
        publish = book.publish
        print(publish.name)

    ### 基于双下划线的跨表查之  一对多
    正向:字段名
    反向:表名小写
    filter,values,values_list(写 __ 跨表)
    # 练习:  查询北京出版社出版过的所有书籍的名字与价格(一对多)
    # SELECT `app01_book`.`name`, `app01_book`.`price` FROM `app01_publish` LEFT OUTER JOIN `app01_book` ON (`app01_publish`.`id` = `app01_book`.`publish_id`) WHERE `app01_publish`.`name` = '北京出版社' ;
   res=models.Publish.objects.filter(name='北京出版社').values('book__name','book__price')
   print(res)
    #SELECT `app01_book`.`name`, `app01_book`.`price` FROM `app01_book` INNER JOIN `app01_publish` ON (`app01_book`.`publish_id` = `app01_publish`.`id`) WHERE `app01_publish`.`name` = '北京出版社';

   res=models.Book.objects.filter(publish__name='北京出版社').values('name','price')
   print(res)


    ## 多对多
    # 练习: 查询 xi出过的所有书籍的名字,价格(多对多)
    #反向
  res=models.Author.objects.filter(name=' xi').values('book__name','book__price')
    print(res)

    # 正向
   res=models.Book.objects.filter(authors__name=' xi').values('name','price')
   print(res)

    #查询 xi的手机号
  res=models.Author.objects.filter(name=' xi').values('author_detail__phone')
  print(res)
  res=models.AuthorDetail.objects.filter(author__name=' xi').values('phone')
  print(res)

	    # 连续跨表
    #查询北京出版社出版过的所有书籍的名字以及作者的姓名
    res=models.Publish.objects.filter(name='北京出版社').values('book__name','book__authors__name')
    print(res)

    res=models.Book.objects.filter(publish__name='北京出版社').values('name','authors__name')
    print(res)

    res=models.Author.objects.filter(book__publish__name='北京出版社').values('book__name','name')
    print(res)

    # 手机号以189开头的作者出版过的所有  书籍名称  以及   出版社名称
    res=models.AuthorDetail.objects.filter(phone__startswith='189').values('author__book__name','author__book__publish__name')
    print(res)


    res=models.Author.objects.filter(author_detail__phone__startswith='189').values('book__name','book__publish__name')
    print(res)

十七、安装模块相关

pip3 install django    
# 本质是去https://pypi.python.org/simple,搜这个模块,会根据你的平台下载在一个安装包(windows平台是whl),下载完,再安装

# pip安装失败的情况
# 我们可以绕过它,有了whl文件以后,自己装
# https://www.lfd.uci.edu/~gohlke/pythonlibs/#opencv
pip3 install django.whl   

# 官方库没有上传到pypi,官方也不给制作whl文件
#如何安装  包 (setup.py)
到达安装目录,setup.py所在的目录
python setup.py build
python setup.py install

# 配置清华源,豆瓣源,本质是
豆瓣源会把pypi,包拉到自己的服务器上,以后你再下,去它的服务器上下,所以速度快

十八、Django版本不同在创建外键是的区别

7 --2.x版本的django
	-外键字段必须加  参数:on_delete
    -1.x版本不需要,默认就是级联删除
    -假设,
    	删除出版社,该出版社出版的所有图书也都删除,on_delete=models.CASCADE
        删除出版社,该出版社出版的图书不删除,设置为空on_delete=models.SET_NULL,null=True
        删除出版社,该出版社出版的图书不删除,设置为默认on_delete=models.SET_DEFAULT,default=0

十九、聚合查询

###########1 聚合查询(聚合函数:最大,最小,和,平均,总个数)
"""D:\Djangozuoye\zuoye1014"""django项目路径

from django.db.models import Avg,Max,Min,Count,Sum
#1 计算所有图书的平均价格
aggregate结束,已经不是queryset对象了
book=models.Book.objects.all().aggregate(Avg('price'))

{'price__avg': 57.0}
# 起别名
book=models.Book.objects.all().aggregate(avg=Avg('price'))

{'avg': 57.0}
#2 计算总图书数
book = models.Book.objects.all().aggregate(count=Count('id'))

{'count': 10}
# 3 计算最低价格的图书
book = models.Book.objects.all().aggregate(min=Min('price'))

{'min': Decimal('6.00')}
# 4 计算最大价格图书
book = models.Book.objects.all().aggregate(max=Max('price'))

{'max': Decimal('120.00')}

print(book)

二十、分组查询

 ####2  分组查询
    '''
       查询每一个部门名称以及对应的员工数
       book:
       id  name   price      publish
        1   金品   11.2        1
        2   西游   14.2        2
        3   东游   16.2        2
        4   北邮   19.2        3
        
    '''
    # 示例一:查询每一个出版社id,以及出书平均价格
    select publish_id,avg(price) from app01_book group by publish_id;
    SELECT publish_id,AVG(price),GROUP_CONCAT(id) FROM app01_book GROUP BY publish_id;
    # annotate


    #  annotate() 内写聚合函数
    #  values在前表示group by的字段
    #  values在后表示取某几个字段
    #  filter在前表示where
    #  filter在后表示having
    from django.db.models import Avg, Count, Max, Min
	# 查询每个出版社出版图书的平均价格和出版社名称   
ret=models.Book.objects.values('publish_id').annotate(avg=Avg('price')).values('publish_name','avg')
    print(ret)

    
    <QuerySet [{'publish__name': '沙河出版社', 'avg': 46.25}, {'publish__name': '人民出版社', 'avg': 52.333333}, {'publish__name': '瑶池出版社', 'avg': 76.0}]>
    
    # 查询出版社id大于1的出版社id,以及出书平均价格
   select publish_id,avg(price) from app01_book where publish_id>1 group by publish_id;

   
 ret = models.Publish.objects.filter(id__gt=1).annotate(avg=Avg('book__price')).values('id', 'avg')   
   
 ret = models.Book.objects.filter(publish_id__gt=1).values('publish__id').annotate(avg=Avg('price')).values('publish__id', 'avg')   
    ret=models.Book.objects.values('publish_id').filter(publish_id__gt=1).annotate(avg=Avg('price')).values('publish_id','avg')
    
    print(ret)
    
    
    <QuerySet [{'publish__id': 2, 'avg': 52.333333}, {'publish__id': 3, 'avg': 76.0}]>

    # 查询出版社id大于1的出版社id,以及出书平均价格大于60的
    select publish_id,avg(price)as avg from app01_book where publish_id>1 group by publish_id HAVING avg>60;
    ret = models.Book.objects.values('publish_id').filter(publish_id__gt=1).annotate(avg=Avg('price')).filter(avg__gt=60).values('publish_id', 'avg')
    print(ret)

	<QuerySet [{'publish__id': 3, 'avg': 76.0}]>
    ## 查询每一个出版社出版的书籍个数
    # pk 代指主键

    ret=models.Book.objects.get(pk=1)
    print(ret.name)
    ret=models.Publish.objects.values('pk').annotate(count=Count('book__id')).values('name','count')
    print(ret)
    
    
    <QuerySet [{'name': '沙河出版社', 'count': 4}, 
               {'name': '人民出版社', 'count': 3}, 
               {'name': '瑶池出版社', 'count': 3}]>

    # 如果没有指定group by的字段,默认就用基表(Publish)主键字段作为group by的字段
    ret=models.Publish.objects.annotate(count=Count('book__id')).values('name','count')
    print(ret)

    <QuerySet [{'name': '沙河出版社', 'count': 4}, 
               {'name': '人民出版社', 'count': 3}, 
               {'name': '瑶池出版社', 'count': 3}]>

    
    # 另一种方式实现
    ret=models.Book.objects.values('publish_id').annotate(count=Count('id')).values('publish__name','count')
    print(ret)

<QuerySet [{'name': '沙河出版社', 'count': 4}, 
           {'name': '人民出版社', 'count': 3}, 
           {'name': '瑶池出版社', 'count': 3}]>

    #查询每个作者的名字,以及出版过书籍的最高价格(建议使用分组的表作为基表)
    # 如果不用分组的表作为基表,数据不完整可能会出现问题
    ret=models.Author.objects.values('pk').annotate(max=Max('book__price')).values('name','max')

    ret = models.Author.objects.annotate(max=Max('book__price')).values('name', 'max')

    ret= models.Book.objects.values('authors__id').annotate(max=Max('price')).values('authors__name','max')
    print(ret)
    
    <QuerySet [{'name': '大', 'max': Decimal('120.00')}, 
               {'name': '中', 'max': Decimal('120.00')}, 
               {'name': '小', 'max': Decimal('120.00')}]>

    #查询每一个书籍的名称,以及对应的作者个数

    ret=models.Book.objects.values('pk').annotate(count=Count('author__id')).values('name','count')
    ret=models.Book.objects.annotate(count=Count('author__id')).values('name','count')

    ret=models.Author.objects.values('book__id').annotate(count=Count('id')).values('book__name','count')
    #
    print(ret)

    
    <QuerySet [{'name': '红0', 'count': 3}, 
               {'name': '红楼梦1', 'count': 2}, 
               {'name': '红楼梦', 'count': 2}, 
               {'name': '红楼梦', 'count': 2}, 
               {'name': '红楼梦', 'count': 1}, 
               {'name': '红楼梦', 'count': 1}, 
               {'name': '红6', 'count': 1}, 
               {'name': '红7', 'count': 1}, 
               {'name': '红8', 'count': 1}, 
               {'name': '红9', 'count': 1}]>
    
    #统计不止一个作者的图书
    ret=models.Book.objects.values('pk').annotate(count=Count('authors__id')).filter(count__gt=1).values('name','count')
    ret = models.Author.objects.values('book__id').annotate(count=Count('id')).filter(count__gt=1).values('book__name', 'count')
    print(ret)

    <QuerySet [{'name': '红0', 'count': 3}, 
               {'name': '红楼梦1', 'count': 2}, 
               {'name': '红楼梦', 'count': 2}, 
               {'name': '红楼梦', 'count': 2}]>
    
    # 上述结果可以去重
    res = models.Book.objects.values('pk').annotate(count=Count('author')).filter(count__gt=1).values('name', 'count').distinct()
    
    <QuerySet [{'name': '红0', 'count': 3}, 
               {'name': '红楼梦1', 'count': 2}, 
               {'name': '红楼梦', 'count': 2}]>
    
    # 统计价格数大于10元,作者的图书
    
    ret = models.Book.objects.values('pk').filter(price__gt=10).annotate(count=Count('authors__id')).values('name','count')
    print(ret)

    #统计价格数大于10元,作者个数大于1的图书
    ret = models.Book.objects.values('pk').filter(price__gt=10).annotate(count=Count('authors__id')).filter(count__gt=1).values('name','count')
    print(ret)

二十一、F与Q查询

 # F查询:取出数据库的某个字段的值
    # res = models.Book.objects.values(F('read_num'))  报错
    
	res = models.Book.objects.values('name', read=F('read_num'))
    
    <QuerySet [{'name': '红0', 'read': 1}, 
               {'name': '红楼梦1', 'read': 534}, 
               {'name': '红d楼梦', 'read': 534}, 
               {'name': '红楼梦', 'read': 5344}, 
               {'name': '红楼梦', 'read': 7675}, 
               {'name': '红楼梦', 'read': 3}, 
               {'name': '红6', 'read': 346}, 
               {'name': '红7', 'read': 54}, 
               {'name': '红8', 'read': 546}, 
               {'name': '红9', 'read': 657}]>
    
    # 把read_num都加1
    from django.db.models import F
    ret=models.Book.objects.all().update(read_num=F('read_num')+1)
    print(ret)

    (0.056) UPDATE `app01_book` SET `read_num` = (`app01_book`.`read_num` + 1); args=(1,)
	10

    #查询评论数大于阅读数的书籍
    ret=models.Book.objects.all().filter(speak_num__gt=F('read_num')).values('name')
 

    <QuerySet [{'name': '红0'}, 
               {'name': '红楼梦1'}, 
               {'name': '红楼梦'}, 
               {'name': '红6'}, 
               {'name': '红7'}]>    
        
    ## 查询评论数大于阅读数2倍的书籍
    ret=models.Book.objects.filter(speak_num__gt=F('read_num')*2)
    print(ret)
    
    <QuerySet [{'name': '红0'}, 
               {'name': '红楼梦1'}, 
               {'name': '红楼梦'}, 
               {'name': '红6'}, 
               {'name': '红7'}]>
# Q查询:制造  与或非的条件

    # Q查询:制造  与或非的条件
    # 查询名字叫红楼梦或者价格大于100的书
    from django.db.models import Q
   res = models.Book.objects.filter(Q(name='红楼梦') | Q(price__gt=100)).values('name', 'price')
    
    <QuerySet [{'name': '红楼梦', 'price': Decimal('100.00')}, 
               {'name': '红楼梦', 'price': Decimal('120.00')}, 
               {'name': '红楼梦', 'price': Decimal('100.00')}, 
               {'name': '红楼梦', 'price': Decimal('120.00')}]>
    
    # 查询名字叫红楼梦并且价格大于100的书
    res = models.Book.objects.filter(Q(name__contains='红') & Q(price__lt=100)).values('name', 'price')
    print(res)

	<QuerySet [{'name': '红0', 'price': Decimal('50.00')}, 
               {'name': '红楼梦1', 'price': Decimal('50.00')}, 
               {'name': '红6', 'price': Decimal('6.00')}, 
               {'name': '红7', 'price': Decimal('7.00')}, 
               {'name': '红8', 'price': Decimal('8.00')}, 
               {'name': '红9', 'price': Decimal('9.00')}]>
    
    # 查询名字不为红楼梦的书
    res = models.Book.objects.filter(~Q(name='红楼梦')).values('name')
    print(res)
	
    <QuerySet [{'name': '红0'}, 
               {'name': '红楼梦1'}, 
               {'name': '红6'}, 
               {'name': '红7'}, 
               {'name': '红8'}, 
               {'name': '红9'}]>
    # Q可以嵌套
    res = models.Book.objects.filter((Q(name='红楼梦') & Q(price=100)) | Q(id__lt=2)).values('id','name', 'price')
    print(ret)

    <QuerySet [{'id': 1, 'name': '红0', 'price': Decimal('50.00')}, 
               {'id': 3, 'name': '红楼梦', 'price': Decimal('100.00')}, 
               {'id': 5, 'name': '红楼梦', 'price': Decimal('100.00')}]>

二十二、原生SQL

    # 原生sql(有些sql用orm写不出来)
    # 两种方案
    # 第一种:用的比较少

    from django.db import connection
    #
    cursor = connection.cursor()
    #
    cursor.execute('select * from app01_book where id < %s', [2])
    #
    # # row = cursor.fetchone()
    row = cursor.fetchall()
    print(row)


    ((1, '红0', Decimal('50.00'), datetime.datetime(2017, 10, 14, 18, 32, 48, 720483), 1, 2, 3465),)
    
    
    # 第二种,用的多
    books=models.Book.objects.raw('select * from app01_book where id <2')
    print(books)#RawQuerySet对象
    for book in books:
        print(book.id)
        print(book.name)
        
10

    books=models.Book.objects.raw('select * from app01_publish where id < 3')
    
    for book in books:
        print(book.__dict__)
        print(book.id)
        print(book.name)
        print(book.addr)
        print(book.price)

{'_state': <django.db.models.base.ModelState object at 0x0000000003FF7190>, 'id': 1, 'name': '沙河出版社', 'addr': '北京', 'phone': '0526-123'}
1
沙河出版社
北京
50.00
{'_state': <django.db.models.base.ModelState object at 0x0000000003FF72B0>, 'id': 2, 'name': '人民出版社', 'addr': '上海', 'phone': '0527-456'}
2
人民出版社
上海
50.00

(0.012) select * from app01_publish where id < 3; args=()
(0.000) SELECT VERSION(); args=None
(0.000) SELECT `app01_book`.`id`, `app01_book`.`price` FROM `app01_book` WHERE `app01_book`.`id` = 1; args=(1,)
(0.009) SELECT `app01_book`.`id`, `app01_book`.`price` FROM `app01_book` WHERE `app01_book`.`id` = 2; args=(2,)

进程已结束,退出代码 0

        
    authors = models.Author.objects.raw('SELECT app01_author.id,app01_author.name,app01_authordetail.sex FROM app01_author JOIN app01_authordetail ON app01_author.author_detail_id = app01_authordetail.id WHERE app01_authordetail.sex = 1')
     
    for author in authors:
       print(author.name)
       print(author.__dict__)

二十三、defer和only

    # defer和only(查询优化相关)
    # 但是只能使用only指定的字段
    books = models.Book.objects.all().only('name')
    # books = models.Book.objects.only('name')
    book = books.first()  # 取第一个值,也支持索引取值
    print(book.name)
    print(book.price)  # 能出来,但是会再次去数据库查询0
50.00

(0.014) SELECT `app01_book`.`id`, `app01_book`.`name` FROM `app01_book` ORDER BY `app01_book`.`id` ASC LIMIT 1; args=()
(0.001) SELECT VERSION(); args=None
(0.001) SELECT `app01_book`.`id`, `app01_book`.`price` FROM `app01_book` WHERE `app01_book`.`id` = 1; args=(1,)

    
    
    # 可以使用defer指定之外的字段,指定的字段使用时需要再次查询,和only相反
    books = models.Book.objects.defer('name')
    book = books.first()
    print(book.name)  # 查询改字段,会再去数据库查询
    print(book.price)
    print(book.id)
    print(book.read_num)
    print(book.speak_num)

    
    
(0.075) SELECT `app01_book`.`id`, `app01_book`.`price`, `app01_book`.`publish_date`, `app01_book`.`publish_id`, `app01_book`.`read_num`, `app01_book`.`speak_num` FROM `app01_book` ORDER BY `app01_book`.`id` ASC LIMIT 1; args=()

(0.001) SELECT VERSION(); args=None

(0.002) SELECT `app01_book`.`id`, `app01_book`.`name` FROM `app01_book` WHERE `app01_book`.`id` = 1; args=(1,)0
50.00
1
2
3465

进程已结束,退出代码 0

二十四、事务的开启

# 事物:ACID,事物的隔离级别(搜),锁, 行级锁,表级锁

    # djanog orm中使用事物:原子性操作,要么都成功,要么都失败

    # 新增一个作者详情,新增一个作者

    # 事物的三个层面
    # 1 局部使用
    from django.db import transaction
    
    with transaction.atomic(): # 都在事物中,要么都成功,要么都失败
        author_detail=models.AuthorDetail.objects.create(addr='瑶池',phone='123',sex=1)
        # raise Exception('抛了异常')
        author=models.Author.objects.create(name='璐璐',age=19,author_detail=author_detail)
        
        
    # 2 视图函数装饰器,这视图函数的执行,将会在一个事务中
    @transaction.atomic
    def index(request):
        return HttpResponse('ok')


    # 3 整个http请求,在事物中,在setting.py中配置(不推荐!!!!!!!!!!!!!)
    '''
    DATABASES = {
        'default': {
            ...
            'PORT': 3306,
            'ATOMIC_REQUEST': True,
       
        }
    }
    
    '''
    'ATOMIC_REQUEST': True,
	设置为True,整个http请求对应的所有sql都放在一个事务中执行(要么所有都成功,要么所有都失败)。




1、脏读:事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据

2、不可重复读:事务 A 多次读取同一数据,事务 B 在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果 不一致。

3、幻读:系统管理员A将数据库中所有学生的成绩从具体分数改为ABCDE等级,但是系统管理员B就在这个时候插入了一条具体分数的记录,当系统管理员A改结束后发现还有一条记录没有改过来,就好像发生了幻觉一样,这就叫幻读。

小结:不可重复读的和幻读很容易混淆,不可重复读侧重于修改,幻读侧重于新增或删除。解决不可重复读的问题只需锁住满足条件的行,解决幻读需要锁表
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值