Django外键字段 多表查询

今日内容概要

  • 神奇的双下划线查询
  • orm创建外键关系
  • 外键字段的增删改查
  • 正反向的概念
  • 多表查询
  • 聚合与分组查询
  • F查询与Q查询

神奇的双下线查询

双下线查询语法

大于		   : __gt
小于		   : __lt
大于等于		   : __gte
小于等于		   : __lte
或者		   : __in   in走索引 not in 不走索引
之间		   : __range
模糊查询		   : __contains
区分大小写	   : __contains
忽略大小写	   : __icontains
以什么开头	   : __startswith
以什么结尾	   : __endswith
查询注册时间	   : register_time__year

双下线查询

# 查询年龄大于20的用户
res = models.User.objects.filter(age__gt=20) 

# 查询年龄小于20的用户
res = models.User.objects.filter(age__lt=20) 

# 成员运算  查询年龄是18,22,25的用户
res = models.User.objects.filter(age__in=[18, 22, 25]) 

# 查询年龄在18到26之间的用户 包含18和26
res = models.User.objects.filter(age__range=[18, 16]) 

# 查询姓名中包含字母j的用户
res = models.User.objects.filter(name__contains='J')  
res = models.User.objects.filter(name__icontains='J')
    '''
        __contains   区分大小写
        __icontains  忽略大小写
    '''

# 查询月份是5月的数据用户
res = models.User.objects.filter(op_time__month=5)  
 # 查询年份是2022年的数据用户
res = models.User.objects.filter(op_time__year=2022) 
    '''
        __year   按照年份筛选数据
        __month  按照月份筛选数据
    '''
# 以字符开头 
res = models.User.objects.filter(name__startswith='j')

# 以字符结尾
res1 = models.User.objects.filter(name__endswith='j')

外键字段的创建

"""
MySQL复习
关系的种类
    一对多关系
    多对多关系
    一对一关系
关系的判断
    换位思考
字段的位置
    一对多关系 外键字段建在多的一方
    多对多关系 外键字段建在第三张关系表中
    一对一关系 外键字段建在任意一方都可以 但是推荐建在查询频率较高的表中
"""
django orm创建表关系
  图书表
  出版社表
  作者表
  作者详情表
关系判断
  书与出版社
    一本书不能对应多个出版社
    一个出版社可以对应多本书
    # 一对多关系 书是多 出版社是一           ForeignKey
    '''django orm外键字段针对一对多关系也是建在多的一方 '''
    
  书与作者
    一本书可以对应多个作者
    一个作者可以对应多本书
    
# 多对多关系      ManyToManyField
    '''django orm外键字段针对多对多关系 可以不用自己创建第三张表'''
  
作者与作者详情
    一个作者不能对应多个作者详情
    一个作者详情不能对个多个作者
    # 一对一关系     OneToOneField
    '''django orm外键字段针对一对一关系 建在查询频率较高的表中'''
 
ManyToManyField不会在表中创建实际的字段 而是告诉django orm自动创建第三张关系表
ForeignKey、OneToOneField会在字段的后面自动添加_id后缀 如果你在定义模型类的时候自己添加了该后缀那么迁移的时候还会再次添加_id_id 所以不要自己加_id后缀


ps:三个关键字里面的参数
    to用于指定跟哪张表有关系 自动关联主键
    to_field\to_fields  也可以自己指定关联字段

外键字段操作

# 一对多、一对一外键字段操作
  增
    publish_id=1             author_detail_id=1
    publish=publish_obj      author_detail=detail_obj
  改
    update(publish_id=3)         update(author_detail_id=3)
    update(publish=publish_obj)  update(author_detail=detail_obj)
 
# 多对多字段操作
  1.第三张关系表创建数据
    book_obj = models.Book.objects.filter(pk=1).first()
    book_obj.authors.add()
        括号内可以放主键值也可以放数据对象 并且都支持多个
  2.第三张关系表修改数据
      book_obj.authors.set()
        括号内必须是一个可迭代对象 元素同样支持主键值或者数据对象
  3.第三张关系表删除数据
      book_obj.authors.remove()
        括号内可以放主键值也可以放数据对象 并且都支持多个
  4.第三张关系表清空指定数据
      book_obj.authors.clear()
        括号内无需传值 直接清空当前表在第三张关系表中的绑定记录

前期建表准备

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_data = models.DateField(auto_now_add=True)

    # 一对多(出版社对书籍)
    publish = models.ForeignKey(to='Publish')

    # 多对多
    authors = models.ManyToManyField(to='Author')

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


# 作者
class Author(models.Model):
    name = models.CharField(max_length=32)
    age = models.IntegerField()

    # 一对一
    author_detail = models.OneToOneField(to='AuthorDetail')


# 作者详情
class AuthorDetail(models.Model):
    phone = models.BigIntegerField()  # 电话号码用BigIntegerField或者直接用CharField
    addr = models.CharField(max_length=64)

多表查询

"""
MySQL多表查询思路
    子查询
        将SQL语句用括号括起来当做条件使用
    连表操作
        inner join\left join\right join\union
        django orm本质还是使用的上述两种方法
    子查询>>>:基于对象的跨表查询
    连表操作>>>:基于双下划线的跨表查询
"""
# 正反向的概念
    核心在于当前数据对象是否含有外键字段 有则是正向 没有则是反向
    正向
      eg:
        由书籍查询出版社 外键字段在书籍表中 那么书查出版社就是'正向'
        由书籍查询作者 外键字段在书籍表中 那么书查作者就是'正向'
        由作者查询作者详情 外键字段在作者表中 那么也是'正向'
    反向
      eg:
        由出版社查询书籍 外键字段不在出版社表 那么出版社查书就是'反向'
      ...
     """
     查询口诀
         正向查询按外键字段名
         反向查询按表名小写
     """
'''
当你的查询结果有多个的时候就需要加.all()
如果是一个则直接拿到数据对象  
'''

# .all()应用场景
1.书籍只能对应一个出版社  不需要.all()

2.书籍可以有可以作者  需要.all()

3.作者只能有一个作者详细信息  不需要.all()

# 编写orm跟编写SQL语句一样 不要总想着一步到位!!!

基于对象的多表查询

"""基于对象的跨表查询本质就是子查询即分步操作即可"""
    # 1.查询数据分析书籍对应的出版社
    # 先获取书籍对象
book_obj = models.Book.objects.filter(title='数据分析').first()
    # 再使用跨表查询
res = book_obj.publish
print(res)  # 出版社对象:北方出版社
    # 2.查询python全栈开发对应的作者
    # 先获取书籍对象
book_obj = models.Book.objects.filter(title='python全栈开发').first()
    # 再使用跨表查询
res = book_obj.authors  # app01.Author.None
res = book_obj.authors.all()
print(res)  # <QuerySet [<Author: 作者对象:jason>, <Author: 作者对象:jerry>]>
    # 3.查询作者jason的详情信息
    # 先获取jason作者对象
author_obj = models.Author.objects.filter(name='jason').first()
    # 再使用跨表查询
res = author_obj.author_detail
print(res)  # 作者详情对象:芜湖

    # 4.查询东方出版社出版的书籍
publish_obj = models.Publish.objects.filter(name='东方出版社').first()
res = publish_obj.book_set  # app01.Book.None
res = publish_obj.book_set.all()
print(res)  # <QuerySet [<Book: 书籍对象:linux云计算>, <Book: 书籍对象:聊斋志异>]>
    # 5.查询jason编写的书籍
author_obj = models.Author.objects.filter(name='jason').first()
res = author_obj.book_set  # app01.Book.None
res = author_obj.book_set.all()
print(res)  # <QuerySet [<Book: 书籍对象:golang高并发>, <Book: 书籍对象:python全栈开发>]>
    # 6.查询电话是110的作者
    author_detail_obj = models.AuthorDetail.objects.filter(phone=110).first()
    res = author_detail_obj.author
    print(res)  # 作者对象:jason

'''
正向什么时候需要加.all()
当你的结果可能有多个的时候就需要加.all()
如果是一个则直接拿到数据对象
'''

基于双下划线的跨表查询

"""基于双下划线的跨表查询本质就是连表操作"""
# 基于双下划线的跨表查询
    """
    查询数据分析书籍对应的价格和出版日期
    models.Book.objects.filter(title='数据分析').values('price','publish_time')
    """
    '''手上有什么条件就先拿models点该条件对应的表名'''
    # 1.查询数据分析书籍对应的出版社名称
res = models.Book.objects.filter(title='数据分析').values('publish__name', 'publish__addr')
print(res)  # <QuerySet [{'publish__name': '北方出版社', 'publish__addr': '北京'}]>
   
 # 2.查询python全栈开发对应的作者姓名和年龄
res = models.Book.objects.filter(title='python全栈开发').values('authors__name','authors__age')
print(res)  # <QuerySet [{'authors__name': 'jason', 'authors__age': 18}, {'authors__name': 'jerry', 'authors__age': 29}]>
  
  # 3.查询作者jason的手机号和地址
res = models.Author.objects.filter(name='jason').values('author_detail__phone','author_detail__addr')
print(res)  # <QuerySet [{'author_detail__phone': 110, 'author_detail__addr': '芜湖'}]>

    # 4.查询东方出版社出版的书籍名称和价格
res = models.Publish.objects.filter(name='东方出版社').values('book__title','book__price')
print(res)  # <QuerySet [{'book__title': 'linux云计算', 'book__price': Decimal('24888.44')}, {'book__title': '聊斋志异', 'book__price': Decimal('16987.22')}]>
  
  # 5.查询jason编写的书籍名称和日期
res = models.Author.objects.filter(name='jason').values('book__title', 'book__publish_time')
print(res)  # <QuerySet [{'book__title': 'golang高并发', 'book__publish_time': datetime.date(2022, 6, 7)}, {'book__title': 'python全栈开发', 'book__publish_time': datetime.date(2022, 2, 28)}]>
   
 # 6.查询电话是110的作者的姓名和年龄
res = models.AuthorDetail.objects.filter(phone=110).values('author__name','author__age')
print(res)  # <QuerySet [{'author__name': 'jason', 'author__age': 18}]>

双下线查询扩展

"""基于双下划线的跨表查询的结果也可以是完整的数据对象"""

'''手上有条件所在的表可以不被models点 直接点最终的目标数据对应的表'''
    # 1.查询数据分析书籍对应的出版社名称
res = models.Publish.objects.filter(book__title='数据分析')
print(res)  # <QuerySet [<Publish: 出版社对象:北方出版社>]>
res = models.Publish.objects.filter(book__title='数据分析').values('name')
print(res)  # <QuerySet [{'name': '北方出版社'}]>
    
# 2.查询python全栈开发对应的作者姓名和年龄
res = models.Author.objects.filter(book__title='python全栈开发').values('name','age')
print(res)  # <QuerySet [{'name': 'jason', 'age': 18}, {'name': 'jerry', 'age': 29}]>
  
  # 3.查询作者jason的手机号和地址
res = models.AuthorDetail.objects.filter(author__name='jason').values('phone','addr')
print(res)  # <QuerySet [{'phone': 110, 'addr': '芜湖'}]>
  
  # 4.查询东方出版社出版的书籍名称和价格
res = models.Book.objects.filter(publish__name='东方出版社').values('title','price')
print(res)  # <QuerySet [{'title': 'linux云计算', 'price': Decimal('24888.44')}, {'title': '聊斋志异', 'price': Decimal('16987.22')}]>
   
 # 5.查询jason编写的书籍名称和日期
res = models.Book.objects.filter(authors__name='jason').values('title','publish_time')
print(res)  # <QuerySet [{'title': 'golang高并发', 'publish_time': datetime.date(2022, 6, 7)}, {'title': 'python全栈开发', 'publish_time': datetime.date(2022, 2, 28)}]>
   
 # 6.查询电话是110的作者的姓名和年龄
res = models.Author.objects.filter(author_detail__phone=110).values('name','age')
print(res)  # <QuerySet [{'name': 'jason', 'age': 18}]>
 


# 连续跨表操作

# 查询python全栈开发对应的作者的手机号res = models.Book.objects.filter(title='python全栈开发').values('authors__author_detail__phone')print(res)  # <QuerySet [{'authors__author_detail__phone': 110}, {'authors__author_detail__phone': 140}]>
res1 = models.AuthorDetail.objects.filter(author__book__title='python全栈开发').values('phone')
print(res1)  # <QuerySet [{'phone': 110}, {'phone': 140}]>


"""
可能出现的不是疑问的疑问:如何获取多张表里面的字段数据
res = models.Book.objects.filter(title='python全栈开发').values('authors__author_detail__phone','authors__name','title')
print(res)
"""

如何查看SQL语句

方式1:如果结果集对象是queryset 那么可以直接点query查看
    res = models.User.objects.values_list('name', 'age')
print(res.query)  # 查看内容封装的SQL语句
SELECT `app01_user`.`name`, `app01_user`.`age` FROM `app01_user`

方式2:配置文件固定配置
     适用面更广 只要执行了orm操作 都会打印内部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',
},
}
}

 

posted @ 2022-05-17 22:42  Yietong  阅读(114)  评论(0)    收藏  举报