Loading

双下划线查询、外键字段的创建、外键字段操作、多表查询、基于双下划线的跨表查询、如何查看ORM操作对应的SQL语句

神奇的双下划线查询

'''
__gt              大于
__lt              小于
__gte             大于等于
__lte             小于等于
__in              成员运算
__range           范围查询

__contains        模糊搜索,区分大小写
__icontains       模糊搜索,忽略大小写
__startswith      指定首字母开头字符
__endswith        指定结尾字符
__regex           用来写正则表达式

__year            按照年份筛选数据
__month           按照月份筛选数据
'''

用法

'''__gt...'''
# 1.查询年龄大于20的用户
# res = models.User.objects.filter(age__lt=40)
'''__in成员运算'''
# 2.查询年龄是18、28、38的用户
# res = models.User.objects.filter(age__in=[18, 28, 38])
'''__range范围查询'''
# 3.查询年龄在18到38之间的用户
# res = models.User.objects.filter(age__range=[18,38])  # 包含18、38
'''模糊查询'''
# 4.查询姓名中包含字母j的用户
# res = models.User.objects.filter(name__contains='J')
# res = models.User.objects.filter(name__icontains='J')
# 4.1其他方法补充
# res = models.User.objects.filter(name__icontains='J',name__startswith='j')  # __startswith 指定首字母开头字符
# res = models.User.objects.filter(name__icontains='J',name__endswith='n')  # __endswith  指定结尾字符
# res = models.User.objects.filter(name__regex='^j')  # __regex 用来写正则表达式
'''__month、__year'''
# 5.查询月份是5月的数据
res = models.User.objects.filter(op_time__month=1)
# 6.查询年份是22年的数据
# res = models.User.objects.filter(op_time__year=2022)
print(res)

外键字段的创建

"""
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  也可以自己指定关联字段

创建图书表代码

from django.db import models


# Create your models here.
class Book(models.Model):
    """图书表"""
    title = models.CharField(max_length=32, verbose_name='书名')
    price = models.DecimalField(max_digits=8, decimal_places=2, verbose_name='价格')  # decimal_places相当于价格后面可以有两个小数点
    publish_time = models.DateField(auto_now_add=True, verbose_name='出版日期')
    # 书与出版社的外键字段 一对多
    publish = models.ForeignKey(to='Publish')  # 默认关联的就是主键字段
    # 书与作者的外键字段 多对多
    authors = models.ManyToManyField(to='Author')  # 自动创建书和作者的第三张表

    def __str__(self):
        return f'书籍对象{self.title}'


class Publish(models.Model):
    """出版社表"""
    name = models.CharField(max_length=32, verbose_name='出版社名称')
    addr = models.CharField(max_length=64, verbose_name='出版社地址')

    def __str__(self):
        return f'出版社对象{self.name}'


class Author(models.Model):
    """作者表"""
    name = models.CharField(max_length=32, verbose_name='姓名')
    age = models.IntegerField(verbose_name='年龄')
    # 作者与作者详情的外键字段 一对一
    author_detail = models.OneToOneField(to='AuthorDetail')

    def __str__(self):
        return f'作者对象{self.name}'


class AuthorDetail(models.Model):
    """作者详情"""
    phone = models.BigIntegerField(verbose_name='手机号')
    addr = models.CharField(max_length=64, verbose_name='家庭地址')

    def __str__(self):
        return f'作者详情对象:{self.addr}'

外键字段操作

一对多、一对一外键字段操作

# 增
# 一对多
publish_id=1  # 直接指定       
publish=publish_obj  # 传入对象
# 一对一
author_detail_id=1  # 直接指定
author_detail=detail_obj  # 传入对象
# 修改关系字段
# 一对多
update(publish_id=3)  # 直接指定 
update(publish=publish_obj)    # 传入对象
# 一对一
update(author_detail_id=3)  
update(author_detail=detail_obj)   # 传入对象

ps:一对多、一对一外键字段操作一致

详细:

# 一对多,一对一外键字段操作
# 新增一本书
# models.Book.objects.create(title='聊斋', price=11111.11, publish_id=1)  # 直接填写关联数据的主键值
# publish_obj = models.Publish.objects.filter(pk=2).first()
# models.Book.objects.create(title='资本论', price=12222.22, publish=publish_obj)  # 也能写数据对象
# models.Author.objects.create(name='tuzi', age=22, author_detail_id=3)
# models.AuthorDetail.objects.create(addr='jialidun', phone=666)
# models.Author.objects.create(name='tuzi', age=22, author_detail_id=3)
# 修改关系字段
# 第一种:
# models.Book.objects.filter(pk=1).update(publish_id=2)
# 第二种
# publish_obj = models.Publish.objects.filter(pk=1).first()
# models.Book.objects.filter(pk=1).update(publish=publish_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()
'''括号内无需传值 直接清空当前表在第三张关系表中的绑定记录'''

详细:

'''1.添加关系'''
# book_obj = models.Book.objects.filter(pk=1).first()
# print(book_obj)
# 方法一
# book_obj.authors.add(1)  # 在第三张关系表中添加数据
# book_obj.authors.add(1,2)  # 在第三张关系表中添加数据
# 方法二
# author_obj1 = models.Author.objects.filter(pk=1).first()
# author_obj2 = models.Author.objects.filter(pk=2).first()
# book_obj.authors.add(author_obj1)
# book_obj.authors.add(author_obj1,author_obj2)

'''2.第三张关系表修改数据'''
# book_obj = models.Book.objects.filter(pk=1).first()
# print(book_obj)
# 第一种:
# book_obj.authors.set([3, ])  # 需要放入可迭代对象,不能直接写数字
# book_obj.authors.set([1,2, ])  # 可以放入多个
# 第二种
# author_obj1 = models.Author.objects.filter(pk=1).first()
# author_obj2 = models.Author.objects.filter(pk=2).first()
# book_obj.authors.set([author_obj1,])
# book_obj.authors.set([author_obj1,author_obj2])

'''3.移除关系'''
# 第一种
# book_obj = models.Book.objects.filter(pk=1).first()
# book_obj.authors.remove(2)
# book_obj.authors.remove([1, 2])
# 第二种
# author_obj1 = models.Author.objects.filter(pk=1).first()
# author_obj2 = models.Author.objects.filter(pk=2).first()
# book_obj.authors.remove([author_obj1, ])
# book_obj.authors.remove([author_obj1, author_obj2])
'''4.第三张关系表清空指定数据'''
book_obj = models.Book.objects.filter(pk=1).first()
book_obj.authors.clear()  # 括号内无需传值,直接清空当前表在第三章关系表中的绑定记录

多表查询

"""
MySQL多表查询思路
	子查询
		将SQL语句用括号括起来当做条件使用
	连表操作
		inner join\left join\right join\union
django orm本质还是使用的上述两种方法
	子查询>>>:基于对象的跨表查询
	连表操作>>>:基于双下划线的跨表查询
"""

正反向的概念

'''核心在于当前数据对象是否含有外键字段 有则是正向 没有则是反向'''
# 正向
eg:
  由书籍查询出版社 外键字段在书籍表中 那么书查出版社就是'正向'
  由书籍查询作者 外键字段在书籍表中 那么书查作者就是'正向'
  由作者查询作者详情 外键字段在作者表中 那么也是'正向'
# 反向
eg:
  由出版社查询书籍 外键字段不在出版社表 那么出版社查书就是'反向'
"""
查询口诀
    正向查询按外键字段名
    反向查询按表名小写
"""
# 编写orm跟编写SQL语句一样 不要总想着一步到位!!!

基于对象的跨表查询

all()针对多对多跨表查询需要加all
_set:如果想通过一的那一方去查找多的一方,由于外键字段不在一这一方,所以用__set来查找即可
    
    
    
    
'正向'
# 1.查询鬼灭之刃数据对应的出版社
# 先获取数据对象
# book_obj = models.Book.objects.filter(title='鬼灭之刃').first()
# 在使用跨表查询
# res = book_obj.publish
# print(res)  # 出版社对象岛国出版社
# 2.查询喜羊羊与灰太狼对应的作者
# 先获取数据对象
# book_obj = models.Book.objects.filter(title='喜羊羊与灰太狼').first()
# 在使用跨表查询
# res = book_obj.authors  # app01.Author.None
# res = book_obj.authors.all()  # <QuerySet [<Author: 作者对象jason>]>
# print(res)
# 3.查询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()  # <QuerySet [<Book: 书籍对象喜羊羊与灰太狼>, <Book: 书籍对象熊出没>, <Book: 书籍对象聊斋>]>
# print(res)

# 5.查询jason编写的书籍
# author_obj = models.Author.objects.filter(name='jason').first()
# res = author_obj.book_set.all()
# print(res)  # <QuerySet [<Book: 书籍对象熊出没>, <Book: 书籍对象鬼灭之刃>, <Book: 书籍对象咒术回战>, <Book: 书籍对象喜羊羊与灰太狼>]>

# 6.查询电话是110的作者
# authordetail_obj = models.AuthorDetail.objects.filter(phone=110).first()
# res = authordetail_obj.author
# print(res)  # 作者对象jason

基于双下划线的跨表查询

"""基于双下划线的跨表查询本质就是连表操作"""
# 基于双下划线的跨表查询
    """
    查询数据分析书籍对应的价格和出版日期
    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.查询喜羊羊与灰太狼对应的作者姓名和年龄
# res = models.Book.objects.filter(title='喜羊羊与灰太狼').values('authors__name','authors__age')
# print(res)  # <QuerySet [{'authors__name': 'jason', 'authors__age': 18}]>
# 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')
# print(res)  # <QuerySet [{'book__title': '喜羊羊与灰太狼'}, {'book__title': '熊出没'}, {'book__title': '聊斋'}]>
# 5.查询jason编写的书籍
# res = models.Author.objects.filter(name='jason').values('book__title','book__publish_time')
# print(res)  # <QuerySet [{'book__title': '熊出没', 'book__publish_time': datetime.date(2022, 5, 1)}, {'book__title': '鬼灭之刃', 'book__publish_time': datetime.date(2020, 8, 20)}, {'book__title': '咒术回战', 'book__publish_time': datetime.date(2019, 6, 7)}, {'book__title': '喜羊羊与灰太狼', 'book__publish_time': datetime.date(2021, 2, 16)}]>
# 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.查询喜羊羊与灰太狼对应的作者姓名和年龄
# res = models.Author.objects.filter(book__title='喜羊羊与灰太狼').values('name', 'age')
# print(res)  # <QuerySet [{'name': 'jason', 'age': 18}]>
# 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': '喜羊羊与灰太狼', 'price': Decimal('9999.99')}, {'title': '熊出没', 'price': Decimal('8888.88')}, {'title': '聊斋', 'price': Decimal('11111.11')}]>
# 5.查询jason编写的书籍
# res = models.Book.objects.filter(authors__name='jason').values('title')
# print(res)  # <QuerySet [{'title': '熊出没'}, {'title': '鬼灭之刃'}, {'title': '咒术回战'}, {'title': '喜羊羊与灰太狼'}]>
# 6.查询电话是110的作者的姓名和年龄
# res = models.Author.objects.filter(author_detail__phone=110).values('name', 'age')
# print(res)  # <QuerySet [{'name': 'jason', 'age': 18}]>

###############################################
'''连续跨表操作'''
# 查询鬼灭之刃对应的作者的姓名、作者的手机号
# res = models.Book.objects.filter(title='鬼灭之刃').values('authors__name','authors__author_detail__phone')
# print(res)  # <QuerySet [{'authors__name': 'jason', 'authors__author_detail__phone': 110}]>
# res = models.AuthorDetail.objects.filter(author__book__title='鬼灭之刃').values('phone', 'author__name')
# print(res)  # <QuerySet [{'phone': 110, 'author__name': 'jason'}]>



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

如何查看ORM操作对应的SQL语句

方式1:如果结果集对象是queryset 那么可以直接点query查看
方式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 20:19  香菜根  阅读(127)  评论(0编辑  收藏  举报