DJango周总结二:模型层,单表,多表操作,连表操作,数据库操作,事务

django周复习二
 1,模型层:
  1单表操作:
   13个必会操作总结
    返回QuerySet对象的方法有
    all()
    filter()
    exclude()
    order_by()
    reverse()
    distinct()
    特殊的QuerySet
    values()       返回一个可迭代的字典序列
    values_list() 返回一个可迭代的元祖序列
    返回具体对象的
    get()
    first()
    last()
    返回布尔值的方法有:
    exists()
    返回数字的方法有
    count()
      增
   # 方式1: create
   # book_obj  = models.Book.objects.create(title='三国',price=19.99,create_time='2019-11-11')
   # print(book_obj.title)
   # 方式2:对象点save()方法   效率极低,因为每执行一次,相当于从数据库从头到尾执行一遍
   # from datetime import datetime
   # ctime = datetime.now()
   # book_obj = models.Book(title='西游记',price=96.66,create_time=ctime)
   # book_obj.save()
   查
   # print(models.Book.objects.all())
   # print(models.Book.objects.get(id=1))
   # print(models.Book.objects.get(pk=1))
   """
   pk会自动查找到当前数据的主键字段
   """
   # print(models.Book.objects.filter(pk=2))
   改
   # 1.update
   # models.Book.objects.filter(pk=1).update(title='三国演义')
   # 2.对象.save()
   # book_obj = models.Book.objects.get(pk=1)
   # book_obj.price = 666.66
   # book_obj.save()
   删除  delete()
   # models.Book.objects.filter(pk=2).delete()
   # < 1 > all(): 查询所有结果
   # < 2 > filter(**kwargs): 它包含了与所给筛选条件相匹配的对象
   # < 3 > get(**kwargs): 返回与所给筛选条件相匹配的对象,返回结果有且只有一个,如果符合筛选条件的对象超过一个或者没有都会抛出错误。(源码就去搂一眼~诠释为何只能是一个对象)
   # < 4 > exclude(**kwargs): 它包含了与所给筛选条件不匹配的对象
   # print(models.Book.objects.exclude(pk=1))  # 只要pk不是1的数据全部查询出来

   # < 5 > order_by(*field): 对查询结果排序('-id') / ('price')
   # print(models.Book.objects.order_by('price'))  # 默认是升序
   # print(models.Book.objects.order_by('-price'))  # 加负号就是降序

   # < 6 > reverse(): 对查询结果反向排序 >> > 前面要先有排序才能反向
   # print(models.Book.objects.order_by('price').reverse())
   # < 7 > count(): 返回数据库中匹配查询(QuerySet)
   # print(models.Book.objects.count())  # 对查询出来的结果进行一个计数

   # 的对象数量。
   # < 8 > first(): 返回第一条记录
   # print(models.Book.objects.filter(pk=1).first())
   # < 9 > last(): 返回最后一条记录
   # print(models.Book.objects.all())
   # print(models.Book.objects.all().last())
   # < 10 > exists(): 如果QuerySet包含数据,就返回True,否则返回False
   # print(models.Book.objects.filter(pk=1000))
   # print(models.Book.objects.filter(pk=1000).exists())

   # < 11 > values(*field): 返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的并不是一系列
   # model的实例化对象,而是一个可迭代的字典序列
   # print(models.Book.objects.values('title','price'))  # 得到的结果是列表套字典
 
   # < 12 > values_list(*field): 它与values()
   # print(models.Book.objects.values_list('title','price'))  # 得到的结果是列表套元组

   # 非常相似,它返回的是一个元组序列,values返回的是一个字典序列
   # < 13 > distinct(): 从返回结果中剔除重复纪录
   """
   去重的前提是 一定要有完全重复的数据 才能去重
   """
   # print(models.Book.objects.filter(title='三国演义').distinct())
   # print(models.Book.objects.values('title','price','create_time').distinct())
   
   
  2,神奇的双下划线查询
    字段__
    __gt   大于
    __lt   小于
    __gte  大于等于
    __lte  小于等于
    __in[]   在不在里面
    __range() 在不在某范围,两边都包含
    __contains='p'   判断是否含有p  只能判断小写
    __icontains='p'  判断是否含有p  忽略大小写
    __startswith='三'  判断是否以三开头
    __endswith='p'     判断是否以p结尾
    __year='2017'     查看2017年的
    
    models.Book.objects.filter(price__gte=200)   大于等于
    models.Book.objects.filter(price__lte=200)  小于等于
    models.Book.objects.filter(price__in=[200,300,666.66])  查询价格要么是200,要么是300,要么是666.66
    models.Book.objects.filter(price__range=(200,800))  # 两边都包含  查询价格在200到800之间的
    models.Book.objects.filter(title__contains='p')  # 仅仅只能拿小写p  查询书籍名字中包含p的
    models.Book.objects.filter(title__icontains='p')  # 忽略大小写
    models.Book.objects.filter(title__startswith='三')          查询书籍是以三开头的
    models.Book.objects.filter(title__endswith='p')
    
    models.Book.objects.filter(create_time__year='2017')    查询出版日期是2017的年(******)
    
  3,多表操作
   一对多:ForeignKey
   一对一:OnoToOneField  可以用ForeignKey代替ForeignKey(unique=True)
    上面两个关键字所创建出来的字段会自动加上_id后缀
   
   多对多:ManyToManyFiled
   该字段并不会真正的在表中展示出来 它仅仅是一个虚拟字段
    1.告诉orm自动创建第三张表
    2.帮助orm跨表查询
    
   
   2.一对多增删改查:
      publish_id传数字                                                          
      models.Book.objects.create(title='三国演义',price=189.99,publish_id=1)     
    publish直接传出版社对象                                                       
      publish_obj = models.Publish.objects.filter(pk=2).first()              
      models.Book.objects.create(title='红楼梦',price=999.99,publish=publish_obj)
                       
      改                                                                      
      传数字的                                                                   
      models.Book.objects.filter(pk=1).update(publish_id=3)                  
      传对象的                                                                   
      publish_obj = models.Publish.objects.filter(pk=2).first()              
      models.Book.objects.filter(pk=1).update(publish=publish_obj)           
                       
      删                                                                      
      models.Publish.objects.filter(pk=2).delete()  # 默认都是级联更新 级联删除          
    
   3,多对多字段的增删改查
     add()       增    传数字,对象
     set()        改   传数字,对象  ,必须是可迭代对象
     remove()     删    传数字,对象
        以上可以传多个
     clear()      删所有   括号内不要传参数
   
     # 增
      add()
      1,add括号中传数字
      
      
          # 主键为6的书籍增加一个作者
        book_obj = models.Book.objects.filter(pk=6).first()
        print(book_obj.authors) 此时为None,就是跳到了第三张表
        
        #对象点击多对多虚拟字段时,会直接多对多的第三张表
        #此时book_obj.authors就是直接跨到第三张表
        book_obj.authors.add(1)  # 此时就是给id为6的书籍添加一个作者
        book_obj.authors.add(2,3)
        # add括号中既可以传一个数字,又可以传多个数字
        # 括号中一个数字,此时就是给id为6的书籍添加一个作者,
        # 所以括号中有几个数字,就是添加几个作者,数字表示的是作者的id号
      
      2,add括号中传对象
        增加一条
            book_obj = models.Book.objects.filter(pk=4).first()
         aut_obj = models.Author.objects.filter(pk=3).first()
         book_obj.authors.add(aut_obj)
        
        增加多条
        
         book_obj = models.Book.objects.filter(pk=5).first()
         book_obj1= models.Book.objects.filter(pk=5).first()
         
         aut_obj = models.Author.objects.filter(pk=2).first()
         aut_obj1= models.Author.objects.filter(pk=1).first()
         aut_obj2 = models.Author.objects.filter(pk=9).first()
         
         book_obj.authors.add(aut_obj,aut_obj1,aut_obj2)
         book_obj1.authors.add(aut_obj1)
        总结:
        add是给书籍添加作者 括号内既可以传数字也可以传作者对象
        并且支持一次性传多个 逗号隔开就可以
        注意 :对象点虚拟字段就是跳到了第三张表
        
        
     改:
      将主键为5的书籍对象 作者修改为2,3
      set()
       括号中以列表的形式,是可迭代对象才可以传一个参数也要以列表的形式
       1,传数字,
       
           book_obj = models.Book.objects.filter(pk=5).first()
        book_obj.authors.set([5,])   传一个参数
        book_obj.authors.set([2,3])  传多个参数
         本质就是修改,有点类似于删除,把不要的删除,把要的留下来
      
       2,传作者对象
       
         aut_obj = models.Author.objects.filter(pk=2).first()
         aut_obj1= models.Author.objects.filter(pk=1).first()
         aut_obj2 = models.Author.objects.filter(pk=9).first()
         
         book_obj.authors.set([aut_obj,aut_obj1,aut_obj2])
   
      总结:
       set()括号内 需要传一个可迭代对象
       可迭代对象  可以是多个数字组合
       也可以是多个对象组合
       但是不能混在一起使用,即不能既有数字,又有对象!!!
       要么纯数字,要么纯对象
       
       
       
     删:
      remove()
       1,传数字
       
          book_obj = models.Book.objects.filter(pk=5).first()
  
       book_obj.authors.remove(3)
       
       2,传对象
       
        aut_obj = models.Author.objects.filter(pk=2).first()
        aut_obj1= models.Author.objects.filter(pk=1).first()
        aut_obj2 = models.Author.objects.filter(pk=9).first()
        
        book_obj.authors.remove(aut_obj)
        book_obj.authors.remove(aut_obj,aut_obj1,aut_obj2)
      总结:
       remove()括号内既可以传数字 也可以传对象
       并且支持传多个,逗号隔开即可
       
       将某本书和作者的关系全部清空,用clear()
       即清空当前这个作者与书籍的关系
       
       book_obj = models.Book.objects.filter(pk=5).first()
       book_obj.authors.clear()
       
       
    跨表查询:
            正向与反向的概念
   
       # 一对一
       # 正向:author---关联字段在author表里--->authordetail  按字段
       # 反向:authordetail---关联字段在author表里--->author  按表名小写
       
        
       # 一对多
       # 正向:book---关联字段在book表里--->publish  按字段
       # 反向:publish---关联字段在book表里--->book  按表名小写_set.all() 因为一个出版社对应着多个图书
       
       # 多对多
       # 正向:book---关联字段在book表里--->author  按字段
       # 反向:author---关联字段在book表里--->book  按表名小写_set.all() 因为一个作者对应着多个图书
       
       
       正向查询按外键字段
       反向查询按表名小写
       
       基于对象的跨表查询(子查询:将一张表的查询结果当做另外一个查询语句的条件)
       
       强调:在书写orm语句的时候 跟写sql语句一样
       不要尝试着 一次性写完  应该做到写一点看一点再一点
   1,如果外键字段在你当前这张表中,那么如果由你当前这张表向另一张表查询就是正向
    关系字段在你当前这张表,由你这张表去查,正向
    关系字段不在你当前这张表,由你这张表去查,反向
    
    正向查询按外键字段
    反向查询按表名小写
    
    
    # 基于对象的跨表查询(子查询:将一张表的查询结果当做另外一个查询语句的条件)
     #查询书籍为4的出版社名称
     book_obj = models.Book.objects.filter(pk=4).first()
     print(book_obj.publish.name)
     print(book_obj.publish.addr)
     # 查询书籍id是5的作者姓名
     book_obj = models.Book.objects.filter(pk=5).first()
     
     print(book_obj.authors)   # app01.Author.None
     #书籍有多个作者,所以拿到为None
     print(book_obj.authors.all()) 拿到的是对象,
     
     当你外键字段对应的值有多个的时候就用all(),为一个的时候就不用all()
       
        # 查询作者是jason的家庭住址
      auth_obj = models.Author.objects.filter(name='jason').first()
      print(auth_obj.author_detail.addr)
     
      
     反向查询:
          # 查询出版社是东方出版社出版的书籍
       publish_obj = models.Publish.objects.filter(name='东方出版社').first()
       print(publish_obj.book_set.all())
       # 查询作者是jason写过的所有书籍
       # auth_obj = models.Author.objects.filter(name='jason').first()
       # print(auth_obj.book_set)
       # print(auth_obj.book_set.all())
       
       # 查询作者号码是120的作者姓名
       auth_obj = models.AuthorDetail.objects.filter(phone=120).first()
       print(auth_obj.author.name)
       print(auth_obj.author.age)
       
     总结:
      反向查询,当你反向查询的结果是多个的时候就需要加 _set
              当你反向查询的结果是一个时就不需要加_set
        即表名小写即可
       跨表查询:可以连续的查询
    # 基于双下划綫的跨表查询(连表查询)
     models.Book.objects.filter().values('publish__name')
     models.Publish.objects.filter(book__title='三').values('name')
     
     models.Book.objects.filter().values('authors__author_detail__phone')
     # 只要表中有外键字段 你可以通过__无限制的跨表 
    
   F与Q
    F查询
    从数据库中获取字段对应的数据
    库存数大于卖出数
   
    Q查询
     与
      filter(Q(),Q())
      filter(Q()&Q())
     或
      filter(Q()|Q())
     非
      filter(~Q())
      
     补充
      q = Q()
      q.connector = 'or'
      q.children.append(('title','三'))
      q.children.append(('price',666))
      models.Book.objects.filter(q)
    
 2,常见字段  
   AutoField()    int primary key auto_increment
   CharField()    varchar()
   IntegerField()   int()
   big....   
   EmailField() varchar(254)
   DateField()      date
   DateTimeField()  datetime
    auto_now:每次修改数据都会更新时间
    auto_now_add:只在第一次创建数据的时候才会更新一次
    
    BooleanField(Field)
     is_delete = BooleanField()
     给该字段传值的时候 你只需要传布尔值即可
     但是对应到数据库  它存的是0和1
    TextField(Field)
     - 文本类型
     用来存大段文本
    
    FileField(Field)
    - 字符串,路径保存在数据库,文件上传到指定目录
    - 参数:
     upload_to = ""      用户上传的文件会自动放到等号后面指定的文件路径中
     storage = None      存储组件,默认django.core.files.storage.FileSystemStorage
   
   自定义char字段
 
    class MyChar(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
   外键字段
    当你在使用django2.X版本的时候 在建立外键关系时(*****)
    需要你手动添加几个关键点参数
     models.cascade
     db_constraints
 3,数据库查询优化
  only与defer
   
  select_releated与prefect_releated
  
  """数据库查询优化"""
   # orm内所有的语句操作 都是惰性查询:只会在你真正需要数据的时候才会走数据库,如果你单单只写orm语句时不会走数据库的
   # 这样设计的好处 在于 减轻数据库的压力 
  # res = models.Book.objects.only('title')
  # # print(res)
  # for r in res:
  #     # print(r.title)  # 只走一次数据库查询
  #     print(r.price)  # 当你点击一个不是only括号内指定的字段的时候 不会报错 而是会频繁的走数据库查询
  # res1 = models.Book.objects.defer('title')  # defer与only是相反的
  # for r in res1:  # defer会将不是括号内的所有的字段信息 全部查询出来封装对象中
  #     # 一旦你点击了括号内的字段  那么会频繁的走数据库查询
  #     print(r.price)
    # select_related与prefetch_related
  # select_related帮你直接连表操作 查询数据   括号内只能放外键字段
  # res = models.Book.objects.all().select_related('publish')
  # for r in res:
  #     print(r.publish.name)
  # res = models.Book.objects.all().select_related('publish__xxx__yyy__ttt')
  # print(res)
  # res = models.Book.objects.all()
  """
  select_related:会将括号内外键字段所关联的那张表  直接全部拿过来(可以一次性拿多张表)跟当前表拼接操作
  从而降低你跨表查询 数据库的压力
  
  注意select_related括号只能放外键字段(一对一和一对多)
   res = models.Book.objects.all().select_related('外键字段1__外键字段2__外键字段3__外键字段4')
  """
  # prefetch_related  不主动连表
  res = models.Book.objects.prefetch_related('publish')
  """
  不主动连表操作(但是内部给你的感觉像是连表操作了)  而是将book表中的publish全部拿出来  在取publish表中将id对应的所有的数据取出
  res = models.Book.objects.prefetch_related('publish')
  括号内有几个外键字段 就会走几次数据库查询操作   
  """
  for r in res:
   print(r.publish.name)
 4,事务
  
  ACID
   原子性
   一致性
   隔离性
   持久性
  from django.db import transaction
  with transaction.atomic():
   """数据库操作
   在该代码块中书写的操作 同属于一个事务
   """
   models.Book.objects.create()
   models.Publish.objects.create()
   # 添加书籍和出版社 就是同一个事务 要么一起成功要么一起失败
  print('出了 代码块 事务就结束')

 5,数据库连接:
  1,在settings.py 文件中进行更改,添加
   DATABASES = {
    'default': {
     'ENGINE': 'django.db.backends.mysql',
     'NAME': 'day56',
     'HOST':'127.0.0.1',
     'USER':'root',
     'PORT':3306,
     'PASSWORD':'123',
     'CHARSET':'utf8'
    }
   }
  2.在应用或者项目文件夹下的__init__文件中添加:
   import pymysql
   pymysql.install_as_MySQLdb()
   
  3,orm对象关系映射
   表        类
   一条条记录   对象
   记录中的字段  对象.属性
   
   
   首先需要在应用下的models.py中书写模型类
    class User(models.Model):
     # 将id字段设置为User表主键字段  在django orm中 你可以不写主键字典  django会默认给你的表创建一个名为id的主键字段
     # id = models.AutoField(primary_key=True)  # 一旦你自己指定了主键字段 那么django就不会自动再帮你创建了
     username = models.CharField(max_length=32)  # username varchar(32)   CharField必须要指定max_length参数
     password = models.IntegerField()  # password int
     
   *************************需要执行数据库迁移(同步)命令******************************
   python3 manage.py makemigrations  # 仅仅是在小本本上(migrations文件夹)记录数据库的修改 并不会直接操作数据
   python3 manage.py migrate  # 将数据库修改记录 真正同步到数据库
   注意:只要动了models中跟数据库相关的代码 就必须重新执行上面的两条命令 缺一不可(******)

你可能感兴趣的:(DJango周总结二:模型层,单表,多表操作,连表操作,数据库操作,事务)