ICode9

精准搜索请尝试: 精确搜索
首页 > 数据库> 文章详细

前期数据准备 pycharm操作数据库 搭建测试环境 ORM关键字 双下划线查询 ORM外键字段创建及操作 多表查询 跨表查询

2022-05-19 01:00:50  阅读:157  来源: 互联网

标签:__ 多表 name objects models res 查询 filter ORM


day55 

 

前期数据准备

  django自带的sqlite3数据库 功能很少 并且针对日期类型不精确

所以使用mysql

 

pycharm操作数据库

1.数据库正向迁移命令(将类操作映射到表中)
    python3 manage.py makemigrations
    python3 manage.py migrate


2.数据库反向迁移命令(将表映射成类)
    python3 manage.py inspectdb

 

搭建测试环境

我们只想操作orm 不想使用网络请求

需要有专门的测试环境

 django是一个整体 不能单独测试一个xxx.py 文件 所以需要搭建测试环境


    1.自己搭建

  在项目里创建一个py文件,名字随意起。在这个py文件里写:

  从manage.py里拷出来的代码。


        import os


            if __name__ == "__main__":
                os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day54.settings")

    # 然后增加两行固定代码:
                import django
                django.setup()

    # 下面是自己写的测试代码:

      pass


    2.pycharm提供


        pycharm ---> python Console

 

orm关键字

<1> all():                 查询所有结果

<2> get(**kwargs):         返回与所给筛选条件相匹配的对象,返回结果有且只有一个,如果符合筛选条件的对象超过一个或者没有都会抛出错误。
 
<3> filter(**kwargs):      它包含了与所给筛选条件相匹配的对象
 
<4> exclude(**kwargs):     它包含了与所给筛选条件不匹配的对象
 
<5> values(*field):        返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的并不是一系列model的实例化对象,而是一个可迭代的字典序列
                            values取具体的数据 是一个对象{},values没有指定参数,获取所有的字段数据,指定参数,获取指定字段数据
 
<6> values_list(*field):   它与values()非常相似,它返回的是一个元组序列,values返回的是一个字典序列
                            values_list取具体的数据 是一个对象(),values_list没有指定参数,获取所有的字段数据,指定参数,获取指定字段数据
    
<7> order_by(*field):      对查询结果排序 ,默认是升序,如果在字段前面加-号就为降序 .示例:models.Person.objects.all().order_by('-id')
                            而且,order_by('-id','name')可以多个字段进行排序
    
<8> reverse():             对查询结果反向排序,请注意reverse()通常只能在具有已定义顺序的QuerySet上调用(在model类的Meta中指定ordering或调用order_by()方法)。

<9> distinct():            从返回结果中剔除重复纪录(如果你查询跨越多个表,可能在计算QuerySet时得到重复的结果。
                           此时可以使用distinct(),注意只有在PostgreSQL中支持按字段去重。)

 
<10> count():              返回数据库中匹配查询(QuerySet)的对象数量。
 
<11> first():              返回第一条记录  # 取不到返回None,不会像索引取不到会报错
 
<12> last():               返回最后一条记录  # 同上
 
<13> exists():             如果QuerySet包含数据,就返回True,否则返回False
                            # 注意get 没有这个方法,只有对象列表才能用这个方法<14> update():        对字段的值进行更新

获取数据

    # res = models.User.objects.all()  # 查询所有的数据                          QuerySet 可以看成是列表套对象

    # res = models.User.objects.filter()  # 括号内填写筛选条件 不写相当于all()      QuerySet 可以看成是列表套对象
    
    # res = models.User.objects.filter(pk=1)  # 想通过主键筛选数据 可以直接写pk 会自动定位到当前表的主键字段 无需你自己查看具体字段名称
    
    # res = models.User.objects.filter(pk=1)[0]  # 直接获取数据对象               QuerySet支持索引取值 但是django不推荐使用 因为索引不存在会直接报错
    
    # res = models.User.objects.filter(pk=1).first()  # 获取结果集中第一个对象     推荐使用封装的方法 不会出现索引超出范围报错的情况
    
    # res = models.User.objects.filter(pk=1, name='kevin').first()  # 括号内支持填写多个筛选条件 默认是and关系
    
    # res = models.User.objects.filter().filter().filter().filter().filter()  # 只要是QuerySet对象就可以继续点对象方法(类似于jQuery链式操作)
    
    # res = models.User.objects.filter().last()  # 获取结果集中最后一个对象
    
    # res = models.User.objects.exclude(name='jason')  # 取反操作 它包含了与所给筛选条件不匹配的对象
    
    # res = models.User.objects.all().values('name','age')  # QuerySet 可以看成是列表套字典
    
    # res = models.User.objects.values('name','age')  # QuerySet 可以看成是列表套字典  指定字段 all不写也表示从所有数据中操作
    
    # res = models.User.objects.filter(pk=2).values('name')  # 可以看成是对结果集进行字段的筛选
    
    # res = models.User.objects.all().values_list('name', 'age')  # QuerySet 可以看成是列表套元组

 数据去重

    # res = models.User.objects.all().distinct()  # 数据对象中如果包含主键 不可能去重

    # res = models.User.objects.values('name').distinct()

 数据排序

# res = models.User.objects.order_by('age')  # 默认是升序
    
    # res = models.User.objects.order_by('-age')  # 该为降序
    
    # res = models.User.objects.order_by('age', 'pk')  # 也支持多个字段依次排序
    
    # res = models.User.objects.reverse()  # 不起作用
    
    # res1 = models.User.objects.order_by('age').reverse()  # 只有在order_by排序之后才可以
    # print(res1)
    
    # res = models.User.objects.order_by('age')

    

 数据取反

    # res = models.User.objects.exclude(name='jason')  # 取反操作

 统计

    # res = models.User.objects.count()  # 统计结果集的个数

判断

    # res = models.User.objects.exists()
    
    # res = models.User.objects.filter(name='jasonNB').exists()  # 判断结果集中是否有数据 有返回True 没有返回False

 

双下划线查询

# 1.查询年龄大于20的用户
# res = models.User.objects.filter(age__gt=20)
# print(res)
"""
    __gt         大于
    __lt         小于
    __gte        大于等于
    __lte        小于等于
    """
# 2.查询年龄是18、22、25的用户
# res = models.User.objects.filter(age__in=[18, 22, 25])
# print(res)
"""
    __in         成员运算
    """
# 3.查询年龄在18到26之间的用户
# res = models.User.objects.filter(age__range=[18, 26])  # 包含18和26
# print(res)
"""
    __range      范围查询
    """
# 4.查询姓名中包含字母j的用户
# res = models.User.objects.filter(name__contains='j')
# res = models.User.objects.filter(name__icontains='j')
# print(res)
"""
    __contains      区分大小写
    __icontains     忽略大小写
    """
# 5.其他方法补充
"""
    __startswith
    __endswith
    __regex
    """
# 6.查询月份是5月的数据
# res = models.User.objects.filter(op_time__month=5)
# print(res)
# 查询年份是22年的数据
res = models.User.objects.filter(op_time__year=2022)
print(res)
"""
    __year          按照年份筛选数据
    __month         按照月份筛选数据
    ...
    """

 

MYSQL回顾

关系的种类
      一对多关系
      多对多关系
      一对一关系


关系的判断
      换位思考


字段的位置
    一对多关系 外键字段建在多的一方
    多对多关系 外键字段建在第三张关系表中
    一对一关系 外键字段建在任意一方都可以 但是推荐建在查询频率较高的表中

 

前期相关配置

settings.py

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': '库名称',
        'HOST':'127.0.0.1',
        'PORT': '3306',
        'USER': 'root',
        'PASSWORD': '123456'  
    }

}

__init__.py

import pymysql

pymysql.install_as_MySQLdb()

models.py

# 图书表

class Book(models.Model):
    title = models.CharField(max_length=32, verbose_name='书名')  # verbose_name用来添加注释
    price = models.DecimalField(max_digits=8, decimal_places=2, verbose_name='价格')  # 8位数的价格 2位是小数
    publish_time = models.DateField(auto_now_add=True, verbose_name='出版日期')

    def __str__(self):
        return '书籍对象:%s' % 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 '出版社对象:%s' % self.name

# 作者表

class Author(models.Model):
    name = models.CharField(max_length=32, verbose_name='姓名')
    age = models.IntegerField(verbose_name='年龄')

# 作者详情表

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

 

ORM外键字段的创建 

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

 

ORM外键字段操作

一对多、一对一  

添加外键字段 create

# 第一种 直接写外键字段对应的值
models.Book.objects.create(title='聊斋志异', price=16987.22, publish_id=1)  # 直接填写关联数据的主键值

# 第二种 先获取一个数据对象 通过数据对象添加
publish_obj = models.Publish.objects.filter(pk=2).first()
models.Book.objects.create(title='资本论', price=56777.98, publish=publish_obj)

 

修改外键字段 update

第一种
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)  # 通过获取的对象修改

 

 多对多

添加关系 add

第一种
book_obj = models.Book.objects.filter(pk=1).first()  # 先获取一本书的对象
book_obj.authors.add(1)  # 用这本书的对象点第三张关系表(书与作者的虚拟表)进行添加数据 这里的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)  # 支持添加多个

 

修改关系 set

第一种
book_obj = models.Book.objects.filter(pk=1).first()  # 同样是先获取一本书对象
book_obj.authors.set([3, ])  # 通过对象点第三张表的方式修改 括号内必须是一个迭代的对象 不然会报错 所以是括号套列表 元素可以单个也可多个
book_obj.authors.set([1, 2])

第二种
author_obj1 = models.Author.objects.filter(pk=3).first()
author_obj2 = models.Author.objects.filter(pk=4).first()
book_obj.authors.set([author_obj1, ])  # 括号内套列表里面放获取到的对象 可以单个也可多个
book_obj.authors.set([author_obj1, author_obj2])

 

删除关系 remove

第一种
book_obj = models.Book.objects.filter(pk=1).first()  
book_obj.authors.remove(3)  # 括号放主键值
book_obj.authors.remove(3,4)  # 也可以移除多个

第二种
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)

 

清空关系 clear

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:
      由出版社查询书籍 外键字段不在出版社表 那么出版社查书就是'反向'
      ...
 	


     查询口诀

         正向查询按外键字段名


         反向查询按表名小写

 


     

 

基于对象的跨表查询

"""基于对象的跨表查询本质就是子查询即分步操作即可"""
		# 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

基于双下划线的跨表查询

"""基于双下划线的跨表查询本质就是连表操作"""
# 基于双下划线的跨表查询
    """
    查询数据分析书籍对应的价格和出版日期
    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查看
方式2:配置文件固定配置
  	适用面更广 只要执行了orm操作 都会打印内部SQL语句

 

标签:__,多表,name,objects,models,res,查询,filter,ORM
来源: https://www.cnblogs.com/jiqiong/p/16286984.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有