django orm多表操作

创建表结构

from django.db import models

class Author(models.Model):
    """
    作者表
    """
    name=models.CharField( max_length=32)
    age=models.IntegerField()
    # authorDetail=models.OneToOneField(to="AuthorDetail",to_field="nid",on_delete=models.CASCADE)  #
    au=models.OneToOneField("AuthorDetail",on_delete=models.CASCADE)
	# 与AuthorDetail表创建一对一对应关系,不写to_field默认会跟AuthorDetail表中的id字段关联
    
class AuthorDetail(models.Model):
    """
    作者详细信息表
    """
    birthday=models.DateField()
    telephone=models.CharField(max_length=11)
    addr=models.CharField(max_length=64)
    # class Meta:
        # db_table='authordetail' #指定表名
        # ordering = ['-id',]
class Publish(models.Model):
    """
    出版社表
    """
    name=models.CharField( max_length=32)
    city=models.CharField( max_length=32)

class Book(models.Model):
    """
    书籍表
    """
    title = models.CharField( max_length=32)
    publishDate=models.DateField()
    price=models.DecimalField(max_digits=5,decimal_places=2)
    publishs=models.ForeignKey(to="Publish",on_delete=models.CASCADE,)
   # ForeignKed是建立外键关联,on_delete是级联删除,如果没有写关联表的关联字段就会默认与被关联表的id字段关联
    authors=models.ManyToManyField('Author',)
    # 执行这个ManyToMany语句会自动创建Book表和Author表关联关系的第三张表

增删查改:

  1. 一对一的增加:两张表是一一对应的关系,(OneToOneField)

    # 第一种方式,使用对象的方式来增加关联字段
    # 先获取被关联字段中的对象,
    obj_aut = models.AuthorDetail.objects.get(nid=4)
    models.Author.objects.create(
            name = '小猿',
            age = '18',
            authorDetail=obj_aut  # 必须写的是Author这个类的authorDetail属性,将关联的字段id以对象的形式传入,它会自动的获取id,并与AuthorDetail表进行关联,
        )
    
    # 第二种方式,使用字段名
    models.Author.objects.create(
            name = '小猿',
            age = '18',
            authorDetail_id=5    # 使用字段名直接将被关联表的id字段进行关联
        )
    

    一对多的增加:(ForeignKey)

    # 跟一对一一样也是有两种创建的方法,
    pub_obj = models.Publish.objects.get(nid=1)
        models.book.objects.create(
            title='白鹿原',
            publishDate='2019-2-3',
            price=213.00,
            publish=pub_obj
        )
    

    多对多的增加:(ManyToManyField)

    # 首先找出几个被关联表的对象
    author1 = models.Author.objects.get(nid=2)
        author2 = models.Author.objects.get(nid=3)
    
        book_obj = models.book.objects.create(
            title='python',
            publishDate='2018-5-4',
            price=562.00,
            publish_id=3,
        )
    	
        # 首先找到这个类创建多对多关联的属性名,直接使用这个属性名就可以对这两张表的关联表进行添加字段值,使用add方式直接添加
       	# 这里有三种添加方式,都可以对关联表进行添加操作
       1.这是获取对象进行添加
        book_obj.authors.add(author1,author2)
        
       2.使用列表的打散方式,进行添加
        book_obj.authors.add(*[2,3])    # 用的多一点
        
       3.直接使用别关联表的id字段就可以进行添加关联
        book_obj.authors.add(2,3)
    
  2. 删除

    1.一对一表的删除,删除时
    # 如果删除的是被关联的表数据,那么关联的表的对应数据也会被删除
    models.AuthorDetail.objects.get(nid=2).delete()
    
    # 如果删除的是关联表的数据,被关联的表不会改变
    models.Author.objects.get(nid=3).delete()
    
    2.一对多表的删除:
    # 如果删除的是被关联的表数据,那么关联的表的对应数据也会被删除
    models.Publish.objects.get(nid=2).delete()
    
    # 如果删除的是关联表的数据,被关联的表不会改变
    models.book.objects.get(nid=6).delete()
    
    3.多对多表的删除:
        # 首先通过类获取对应的数据对象
        book_obj = models.book.objects.get(nid=5) 
        # remove中的数值是表示删除与这个表关联的值为1的这条数据
        book_obj.authors.remove(1)  # 通过对象调用这个类中的authors属性,通过这个属性名来操作第三张表进行相关的操作
        book_obj.authors.clear()  # 清除
        book_obj.authors.set(['1','5'])  # 先清除再添加,相当于修改
    
  3. #两种方式
    1.
    # 通过类获取对应的数据对象
    pub_obj = models.Publish.objects.get(nid=1)
        models.book.objects.filter(nid=3).update(
            title = 'go语言',
            publish = pub_obj,  # 拿到类属性,传入获取的对象进行修改值,自动转换
        )
    
    2.
        models.book.objects.filter(nid=3).update(
            title = 'go语言',
            publish_id = 1,  #直接通过表字段更换关联字段的id
        )
    
  4. 查看

# 关系属性写在表1,关联到表2,那么通过表1的数据去找表2的数据,叫做正向查询,返过来就是反向查询
1. 一对一表查询:
   正向查询
   通过作者名去被关联的表中查找电话号
  # 首先通过类来获取数据对象
  aut_obj = models.Author.objects.filter(name='小猿').first()  
   # 通过这个对象直接调用类中关联字段的属性名authorDetail
  aut_obj.authorDetail.telephone
  
   反向查询
   通过被关联的表中的数据找关联表中的数据
    # 首先通过类来获取数据对象
   phone = models.AuthorDetail.objects.filter(telephone='123').first()
   # 通过这个对象直接后边接上关联的表的类名(小写),在接上自己要查找的属性
   name = phone.author.name
   
2. 一对多查询:
   正向查询:
   查询go语言是哪个出版社出版的?
   book_obj = models.book.objects.get(title='go语言')
   name = book_obj.publish.name
   
   反向查询:
   查询那个出版社出版了那些书?
   pub_obj = models.Publish.objects.get(nid=1)
   book_name = pub_obj.book_set.all()  # 获取到多条数据   类名小写加_set
   for i in book_name:
       print(i.title)
       
3.  多对多
   正向查询
   obj = models.Book.objects.filter(title='海狗的怂逼人生').first()
   ret = obj.authors.all()
   print(ret)  #<QuerySet [<Author: 王洋>, <Author: 海狗>]>
   for i in ret:
       print(i.name)

   查询一下海狗写了哪些书 -- 反向查询
    obj = models.Author.objects.filter(name='海狗').first()
    ret = obj.book_set.all()
    print(ret)
    for i in ret:
        print(i.publishs.name)
        print(i.title)
  1. django为表与表之间存在关联关系提供了一种高效的查询方法 ----- 双下划线的跨表查询(就使用两个下划线来链接模型(model)间关联字段的名称,直到最终链接到你想要的model 为止。)

    #基于双下划线的查询就一句话:正向查询按字段,反向查询按表名小写用来告诉ORM引擎join哪张表,一对一、一对多、多对多都是一个写法,注意,我们写orm查询的时候,哪个表在前哪个表在后都没问题,因为走的是join连表操作。
    
  2. 语法操作

    1.一对一
    	# 查询大猿的电话号码,
        正向:
    	ret = models.Author.objects.filter(name='大猿').values('au__telephone')
        # <QuerySet [{'au__telephone': '456'}]>   获取到的是一个queryset对象,
        首先根据已知条件查询到对应的数据,在加上values,在values中写入关联字段的名称+上下划线+要查询的字段名称
        
        反向:
        ret = models.AuthorDetail.objects.filter(author__name='大猿').values('telephone')
        # <QuerySet [{'telephone': '456'}]>    同样获取到的是一个queryset对象
        反向查询就是通过需要获取信息的这张表来获取数据,查询的条件写已知的作者姓名,后边的values中是需要获取数据的字段名
        
    2.一对多:
    	# 查询北京出版社出版那些书?
        正向:
        ret = models.Publish.objects.filter(name='北京出版社').values('book__title')
        # <QuerySet [{'book__title': '三国'}, {'book__title': '西游记'}]>
        这个需要注意的是在values中的值是表名加字段名"book__title",Book表的名字需要小写
        
        反向:
        ret = models.Book.objects.filter(publishs__name='北京出版社').values('title')
        # <QuerySet [{'title': '三国'}, {'title': '西游记'}]>
        注意在filter中需要写的是关联字段名加双下划线在加字段名
        
        
    3.多对多:
    	#查询三国是哪些作者写的?
        正向:
        ret = models.Book.objects.filter(title='三国').values('authors__name')
    	# <QuerySet [{'authors__name': '大猿'}, {'authors__name': '小猿'}]>
        
        反向:
        ret = models.Author.objects.filter(book__title='三国').values('name')
        # <QuerySet [{'name': '大猿'}, {'name': '小猿'}]>
        
        
    4. related_name
    # 查询一下24期出版社出版了哪些书
    ret = models.Publish.objects.filter(name='24期出版社').values('xxx__title') #xxx代替反向查询的小写表名
    print(ret)
    

聚合查询:

  1. aggregate(*args, **kwargs)

  2. 操作:

    1.查询书籍的平均价格和最大价格
    # 首先需要导入相应的包
    from django.db.models import Avg,Max
    ret = models.Book.objects.all().aggregate(a=Avg('price'),m=Max('price'))
    # ret = models.Book.objects.aggregate(a=Avg('price'),m=Max('price'))  这个也可以查询所有的值
    
    # {'a': 456.4, 'm': Decimal('856.00')}     查出的数据是一个字典不是一个queryset类型的数据,这说明这个不能在对其进行加工,也就是说聚合查询是orm的结束语句
    
    
  3. aggregate()QuerySet 的一个终止子句,意思是说,它返回一个包含一些键值对的字典。键的名称是聚合值的标识符,值是计算出来的聚合值。键的名称是按照字段和聚合函数的名称自动生成出来的。如果你想要为聚合值指定一个名称,可以向聚合子句提供它。

分组查询:

  1. annotate()为调用的QuerySet中每一个对象都生成一个独立的统计值(统计方法用聚合函数)。

  2. 操作

    # 获取每个出版社出版的书的平均价格
    1.
    from django.db.models import Avg,Max
    ret = models.Book.objects.values('publishs_id').annotate(a=Avg('price'))
    # ret = models.Book.objects.values('publishs').annotate(a=Avg('price'))  同样可以
    
    annotate前边的values是分组的依据,annotate是分组的统计数据
    
    ret = models.Book.objects.values('publishs').annotate(a=Avg('price')) #注意:annotate里面必须写个聚合函数,不然没有意义,并且必须有个别名=,别名随便写,但是必须有,用哪个字段分组,values里面就写哪个字段,annotate其实就是对分组结果的统计,统计你需要什么。
    
    2.如果不写分组的依据就会默认以这个表的id字段进行分组,求值时利用了双下划线的查询方式
    from django.db.models import Avg,Max
    ret = models.Publish.objects.annotate(a=Avg("book__price")).values('name','a')
    # <QuerySet [{'name': '北京出版社', 'a': 324.5}, {'name': '上海出版社', 'a': 490.5}, {'name': '深圳出版社', 'a': 652.0}]>
    

F:

  1. 在我们需要对一个表中的几个字段的数据进行比较时,是不是比较麻烦,那么Django 提供 F() 来做这样的比较,F() 的实例可以在查询中引用字段,来比较同一个 model 实例中两个不同字段的值。

  2. 操作:

    1.  将评论数大于点赞数的数据取出
        ret = models.Book.objects.filter(comment__gt=F('good'))
        # <QuerySet [<Book: 红楼梦>]>
        可以看出这样比较会省事,F中所写的字段名就是直接拿出来进行比较
        
    2. 将每个数据的价格增加100
        models.Book.objects.all().update(
            price=F('price')+100    # F获取到price字段对这个字段继续增加
        )
    

Q:

  1. filter() 等方法中的关键字参数查询都是一起进行“AND” 的。 如果你需要执行更复杂的查询(例如OR 语句),你可以使用Q 对象

  2. Q 对象可以使用&(与)|(或)、~(非) 操作符组合起来。当一个操作符在两个Q 对象上使用时,它产生一个新的Q 对象。

  3. 操作:

    1. 查询书籍价格在大于500或者评论数在小于100的书籍
    ret = models.Book.objects.filter(Q(price__gt=500)|Q(comment__lt=100))
    # <QuerySet [<Book: 西游记>, <Book: 水浒传>, <Book: 红楼梦>, <Book: 平凡的世界>]>
    
posted @ 2019-10-13 14:45  adrian-boy  阅读(251)  评论(0编辑  收藏  举报