orm之多表操作

表结构

  • class Book(models.Model):
        nid = models.AutoField(primary_key=True)  # 自增id(可以不写,默认会有自增id)
        title = models.CharField(max_length=32)
        publishDdata = models.DateField()  # 出版日期
        price = models.DecimalField(max_digits=5, decimal_places=2)  # 一共5位,保留两位小数
    
        #一个出版社有多本书,关联字段要写在多的一方
        # 不用命名为publish_id,因为django为我们自动就加上了_id
        publish = models.ForeignKey("Publish")  #foreignkey(表名)建立的一对多关系
        # publish是实例对象关联的出版社对象
        authorlist = models.ManyToManyField("Author")  #建立的多对多的关系
        def __str__(self):  #__str__方法使用来吧对象转换成字符串的,你返回啥内容就打印啥
            return self.title
    class Publish(models.Model):
        #不写id的时候数据库会自动给你增加自增id
        name =models.CharField(max_length=32)
        addr = models.CharField(max_length=32)
    
        def __str__(self):
            return self.name
    class Author(models.Model):
        name = models.CharField(max_length=32)
        age = models.IntegerField()
    
    class AuthorDeital(models.Model):
        tel = models.IntegerField()
        addr = models.CharField(max_length=32)
        author = models.OneToOneField("Author")  #建立的一对一的关系
    
  • 建立一对一的关系

    • OneToOneField()

    • 就是foreignkey+unique,只不过不需要我们自己来写参数了,并且orm会自动帮你给这个字段名字拼上一个_id,数据库中字段名称为authorDetail_id
      
    • au=models.OneToOneField("AuthorDetail",on_delete=models.CASCADE)
      
  • 建立一对多的关系

    • ForeignKey()

    • publishs=models.ForeignKey(to="Publish",on_delete=models.CASCADE,)
      
  • 建立多对多关系

    • ManyToManyField可以建在两个模型中的任意一个,自动创建第三张
      
  • 注意

    • 临时添加的字段,首先得考虑之前的数据有没有,设置一个默认值

    • 1、 表的名称myapp_modelName,是根据 模型中的元数据自动生成的,也可以覆写为别的名称  

      2、id 字段是自动添加的

      3、对于外键字段,Django 会在字段名上添加"_id" 来创建数据库中的列名

      4、这个例子中的CREATE TABLE SQL 语句使用PostgreSQL 语法格式,要注意的是Django 会根据settings 中指定的数据库类型来使用相应的SQL 语句。

      5、定义好模型之后,你需要告诉Django _使用_这些模型。你要做的就是修改配置文件中的INSTALL_APPSZ中设置,在其中添加models.py所在应用的名称。

      6、外键字段 ForeignKey 有一个 null=True 的设置(它允许外键接受空值 NULL),你可以赋给它空值 None 。

logging-SQL语句

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

增删改查

1,增

  • 一对多添加

    • # 一对多的添加
          # 方式一:如果是这样直接指定publish_id字段去添加值,前提是你的主表里面必须有数据
          # 主表:没有被关联的(因为book表是要依赖于publish这个表的)也就是publish表
          # 子表:关联的表
          models.Book.objects.create(title="追风筝的人",publishDdata="2015-5-8",price="111",publish_id=1)
          # 方式二:推荐
          pub_obj = models.Publish.objects.filter(name="人民出版社")[0]
          print(pub_obj)
          models.Book.objects.create(title = "简爱",publishDdata="2000-6-6",price="222",publish=pub_obj)
      
          # 方式三:save
          pubObj= models.Publish.objects.get(name="人民出版社") #只有一个的时候用get,拿到的直接就是一个对象
          bookObj = models.Book(title = "真正的勇士",publishDdata="2015-9-9",price="50",publish=pubObj)
          bookObj.save()
      
  • 多对多添加的两种方式

    • # 多对多的添加的两种方式
          # 方式一:
          # 先创建一本书:
          pub_obj=models.Publish.objects.filter(name="江南出版社").first()
          book_obj = models.Book.objects.create(title="醉玲珑",publishDdata="2015-4-10",price="222",publish=pub_obj)
          # #通过作者的名字django默认找到id
          haiyan_obj = models.Author.objects.filter(name="haiyan")[0]
          egon_obj = models.Author.objects.filter(name="egon")[0]
          xiaoxiao_obj = models.Author.objects.filter(name="xiaoxiao")[0]
          # 绑定多对多的关系、
          book_obj.authorlist.add(haiyan_obj, egon_obj, xiaoxiao_obj)
      
          # 方式二=========,查出所有的作者
          pub_obj = models.Publish.objects.filter(name="江南出版社").first()
          book_obj = models.Book.objects.create(title="醉玲珑", publishDdata="2015-4-10", price="222", publish=pub_obj)
          authers = models.Author.objects.all()
          # #绑定多对多关系
          book_obj.authorlist.add(*authers)
      

2,删

  • remove:将某个特定的对象从被关联对象集合中去除,即解除关联关系

    •  # 解除多对多的关系(remove)
          book_obj=models.Book.objects.filter(title="醉玲珑").last() #找到书对象
          authers=models.Author.objects.filter(id__lt=3)  #找到符合条件的作者对象
          book_obj.authorlist.remove(*authers) #因为清除的是多条,得加个*
      
  • 清除绑定:clear

    • 清空被关联对象集合

    •  # 清除关系方法(clear)
          book_obj= models.Book.objects.filter(title="红楼梦")
          for book_obj_item in book_obj:#把所有红楼梦的都给清空了
              book_obj_item.authorlist.clear()
      
  • 两者区别:

    • remove:先将要清除的数据筛选出来,然后移除
    • clear:不用查,直接就把数据都清空了。
    • 各有应用场景

3,改

  • 改和查一样

4,查

  • 一对一查询记录

    • 正向查询:按字段属性
    • 反向查询:按表名,一对一用不到_set
  • 一对多查询记录

    • 正向查询:按字段属性
    • 反向查询:按表名_set
  • 多对多查询记录

    • 正向查询:按字段属性
    • 反向查询:按表名__set
  • related_name:别名

    • 你可以通过在 ForeignKey() 和ManyToManyField的定义中设置 related_name 的值来覆写 FOO_set 的名称。例如,如果 Article model 中做一下更改: publish = ForeignKey(Blog, related_name='bookList'),那么接下来就会如我们看到这般:

      # 查询 人民出版社出版过的所有书籍
       
         publish=Publish.objects.get(name="人民出版社")
       
         book_list=publish.bookList.all()  # 与人民出版社关联的所有书籍对象集合
      

双下划线的跨表查询

  • 正向查询:按字段属性
  • 反向查询:按表名____
  • 先筛选,然后通过跨表查值的方法

聚合查询

  • aggregate(*args, **kwargs),只对一个组进行聚合

  • SQL原生语句中的聚合为group by

  • aggregate()是QuerySet的一个终止子句,也就是不在返回一个QuerySet集合,他返回一些键值对

  • from django.db.models import Avg, Sum, Count, Max, Min
    
    #查询所有图书的平均价格
    ret = models.Book.objects.all().aggregrate(Avg("price"))
    print(ret)
    

分组查询

  • annotate():为QuerySet中每一个对象都生成一个独立的汇总值,是对分组完之后的结果进行聚合

  • from django.db.models import Count
    
    #统计每一本书的作者个数
    方式一:
    ret = models.Book.objects.all().annotate(authorNum = Count("authorlist__name")).values("authorNum")
    #values中的内容就是要分组的内容,
    
    #统计不止一个作者的书
    ret = models.Book.objects.annotate(num_authors=Count("authorlist__name")).filter(num__gt=1).values("title","num_authors")
    
    #统计各个作者出书的总价格
    ret = models.Author.objects.all().annotate(pricrSum = Sum("book__price")).values("name","priceSum")
    
  • 总结

    • 按什么分组就以它作为基表
    • values在前,表示group by,也可以省略不写,默认为pk =====在后,表示取值,
    • filter在前,表示where条件====在后表示having
    • 在前与在后比较的是annotate()

F查询和Q查询

1,F查询

  • Django内置提供的F(),可以在查询中引用字段,来比较同一个model实例中两个不同字段的值

  • 
    from django.db.models import F
      前面的filter里面都是用字段与一个常量比较, 如果要比较的是两个字段呢,就需要借助F函数了
    
      不只是filter, 其他地方也可以用, 比如update
    
      用的时候将F()包裹某个字段就能拿到它的值了
    
      现将Book表插入阅读数与评论数两个字段后执行数据库迁移命令
    
      eg: 查询评论数大于阅读数的书
      	Book.objects.all().filter(commit_num__gt=F('read_num'))
    
      eg: 把所有书的评论数加1
      	Book.objects.all().update(commit_num=F('commit_num')+1)
      	
      eg: 把python这本书的阅读数减5
      	Book.objects.all().filter(name='python').update(reat_num=F('reat_num') - 5)
    

Q查询

  • filte() 筛选中的关键字参数都是一起进行’AND’的,如果需要执行跟复杂的查询,例如or语句,则需要使用Q对象

  • &————与

  • |—————或

  • ~————非

  • 将两个条件分别用Q()包裹,中间放与或非符号

  • '''
    filter里面放多个条件时我们用逗号隔开他默认是and的关系

    Q函数是为了表示 与& , 或|, 非~ 的

    将两个条件分别用Q()包裹中间放与或非符号

    导入Q函数
    from django.db.models import Q

    eg: 查询作者名字是江南或者名字是egon的书的书名和作者
    Book.objects.all().filter(Q(authors__name='江南') | Q(authors__name='egon')).values('name','authors__name')

    eg: 查询作者不是江南的书
    Book.objects.filter(~Q(authors__name='江南'))
    '''

posted @ 2019-12-16 17:27  阿浪阿浪  阅读(195)  评论(0编辑  收藏  举报