• 开发工程师必备————【Day29】Django补充(四)


    今日内容详细

    • 表查询数据准备及测试环境搭建
    • 表查询关键字
    • 外键创建
    • 外键数据增删改查
    • 多表查询(子查询、连表操作)

    表查询数据准备及测试环境搭建

    1.django自带一个sqlite3小型数据库
    说明:该数据库功能非常有限,并且针对日期类型的数据兼容性很差。

    2. django切换MySQL数据

    • django1.X版本
    导入模块pymysql:
    
    import pymysql
    	pymysql.install_as_MySQLdb()
    
    • 1
    • 2
    • 3
    • 4
    • django2.X 3.X 4.X
    下载mysqlclient模块:
    
    pip install mysqlclient
    
    • 1
    • 2
    • 3

    3.定义模型类

    class User(models.Model):
       uid = models.AutoField(primary_key=True,verbose_name='编号')
       name = models.CharField(max_length=32,verbose_name='姓名')
       age = models.IntegerField(verbose_name='年龄')
       join_time = models.DateField(auto_now_add=True)
    
       """
       auto_now:每次操作数据并保存都会自动更新当前时间;
       auto_now_add:只在创建数据的那一刻自动获取当前时间,之后如果不认为更改则不变。
       """
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    4.执行数据库迁移命令(模型类>>>表)
    makemigrations
    migrate

    5.模型层测试环境准备

    • 方式1:在任意空的py文件中准备环境(拷贝manage.py文件内一部分代码)
    import os
    def main():
       os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'day59.settings')
       # 必须要等到上述环境准备好才可以导下面django和models模块!!!
       import django
       django.setup()
    
       from app01 import models
       print(models.User.objects.filter())
    
    if __name__ == '__main__':
       main()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 方式2:pycharm提供测试环境
      python console命令行测试环境
      请添加图片描述

    ORM常见查询关键字

    1/扩展知识点

    • 当需要查询数据主键字段值的时候,可以使用pk忽略掉数据字段真正的名字;
    • 在模型类中可以定义一个__str__方法,便于后续数据对象被打印展示的是查看方便;
    • Queryset中如果是列表套对象那么直接for循环和索引取值但是索引不支持负数;
    • 虽然queryset支持索引但是当queryset没有数据的时候索引会报错 推荐使用first。

    2.常见查询关键字
    (1)批量操作数据。

    • create()
      创建数据方式一,返回值就是当前创建的数据对象;
    import os
    def main():
       os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'day59.settings')
       import django
       django.setup()
       from app01 import models
       res = models.User.objects.create(name='kevin',age=28)
       print(res.name)    # kevin
       print(res.age)     # 28
       print(res.join_time)    # 2022-09-13
       print(res.pk)          # 3
    
    if __name__ == '__main__':
       main()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    创建对象方式二:还可以利用类实例化对象然后调用save方法创建

       user_obj = models.User(name='oscar',age=28)
       user_obj.save()
    
    • 1
    • 2
    • update
      更新数据
    models.User.objects.filter(pk=5).update(name='jasonnb')
    
    • 1
    • delete()
      删除数据
    models.User.objects.filter(pk=2).delete()
    
    • 1

    (2)13种必会操作。

    • filter()
      筛选数据,返回值是一个QuerySet(可以看成是列表套数据对象)
      (1)括号内不写查询条件 默认就是查询所有
    res = models.User.objects.filter()
       print(res)   # , , , , ]>
    
    • 1
    • 2

    (2)括号内可以填写条件 并且支持多个 逗号隔开 默认是and关系

       res = models.User.objects.filter(name='oscar',age=28)
       print(res)      # ]>
    
    • 1
    • 2
    • all()
      查询所有数据 返回值是一个QuerySet(可以看成是列表套数据对象),即可以for循环取值以及索引取值。
       res = models.User.objects.all()  
       print(res)    # , , , , ]>    
    
    • 1
    • 2
    • first()
      获取Queryset中第一个数据对象 如果为空则返回None
       res = models.User.objects.all()
       print(res)    # , , , , ]>
       print(res.first())   # 对象:jason
    
    • 1
    • 2
    • 3
    • last()
      获取Queryset中最后一个数据对象 如果为空则返回None
       res = models.User.objects.last()
       print(res) # 对象:oscar
    
    • 1
    • 2
    • get()
      直接根据条件查询具体的数据对象 但是条件不存在直接报错 不推荐使用
       res = models.User.objects.get(pk=3)
       print(res)    # 对象:kevin
    
    • 1
    • 2
    • values()
      指定查询字段 结果是Queryset(可以看成是列表套字典数据)
    res = models.User.objects.values('name','age')
       print(res)    # 
    
    • 1
    • 2
    • values_list()
      指定查询字段 结果是Queryset(可以看成是列表套元组数据)
    res = models.User.objects.values_list('name','join_time')
       print(res)   # 
    
    • 1
    • 2
    • order_by()
      指定字段排序 默认是升序 在字段前加负号则为降序 并且支持多个字段排序
    res = models.User.objects.order_by('age')  # 升序
       print(res)   # , , , , ]>
       res = models.User.objects.order_by('-age')   # 降序
       print(res)   # , , , , ]>
    
    • 1
    • 2
    • 3
    • 4
    • count()
      统计orm查询之后结果集中的数据格式
       res = models.User.objects.all().count()
       print(res)   # 5
    
    • 1
    • 2
    • distinct()
      针对重复的数据集进行去重 一定要注意数据对象中的主键(带主键后不能去重)
    res = models.User.objects.values('name','age').distinct()
       print(res)   # 
    
    • 1
    • 2
    • exclude()
      针对括号内的条件取反进行数据查询 QuerySet(可以看成是列表套数据对象)
    res = models.User.objects.exclude(pk = 1)
       print(res)  # , , , ]>
    
    • 1
    • 2
    • reverse()
      针对已经排了序的结果集做颠倒
    res = models.User.objects.all().order_by('age')
       print(res.reverse())  # , , , , ]>
    
    • 1
    • 2
    • exists()
      判断查询结果集是否有数据 返回布尔值 但是几乎不用因为所有数据自带布尔值
       res = models.User.objects.filter(pk=100).exists()
       print(res)    # False
    
    • 1
    • 2
    • raw()

    执行SQL语句;

    res = models.User.objects.raw('select * from app01_user')
       print(res)   # 原生sql语句:
    
    • 1
    • 2

    还可以借助于模块。

     from django.db import connection  
       cursor = connection.cursor()  
       cursor.execute("insert into hello_author(name) VALUES ('郭敬明')") 
       cursor.execute("update hello_author set name='韩寒' WHERE name='郭敬明'")  
       cursor.execute("delete from hello_author where name='韩寒'")  
       cursor.execute("select * from hello_author")  
       cursor.fetchone()  
       cursor.fetchall()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    神奇的双下划线的查询

    1.比较运算符

    • 字段__gt(大于)
    res = models.User.objects.filter(age__gt=20)
       print(res)   # , , ]>   
    
    • 1
    • 2
    • 字段__lt(小于)
       res = models.User.objects.filter(age__lt=20)
       print(res)   # , ]>
    
    • 1
    • 2
    • 字段__gte(大于等于)
       res = models.User.objects.filter(age__gte=18)
       print(res)   # , , , , ]>
    
    • 1
    • 2
    • 字段__lte (小于等于)
       res = models.User.objects.filter(age__lte=18)
       print(res)    # , ]>
    
    • 1
    • 2

    2.成员运算符

    • 字段__in
       res =models.User.objects.filter(name__in=['jason','kevin'])
       print(res)   # , , , ]>
    
    • 1
    • 2

    3.范围查询(数字)
    字段__range

       res = models.User.objects.filter(age__range=(20,30))
       print(res)   # , , ]>
    
    • 1
    • 2

    4.模糊查询

    • 字段__contains(不忽略大小写)
       res = models.User.objects.filter(name__icontains='j')
       print(res)  # , ]>
    
    • 1
    • 2
    • 字段__icontains(忽略大小写)
    res = models.User.objects.filter(name__contains='j')
       print(res)  # , ]>
    
    • 1
    • 2

    5.日期处理

    • 字段__year
       res = models.User.objects.filter(join_time__year=2022)
       print(res)  # , , , , ]>
    
    • 1
    • 2
    • 字段__month
    res = models.User.objects.filter(join_time__month=9)
       print(res) # , , , , ]>
    
    • 1
    • 2
    • 字段__day
    res = models.User.objects.filter(join_time__day=13)
       print(res) # , , , , ]>
    
    • 1
    • 2

    查看ORM底层SQL语句

    方式1(局限性比较强):
    如果是Queryset对象,那么可以直接点query查看SQL语句。

    举个栗子:
    res = models.User.objects.filter(join_time__month=9)
       print(res.query)  # SELECT `app01_user`.`uid`, `app01_user`.`name`, `app01_user`.`age`, `app01_user`.`join_time` FROM `app01_user` WHERE EXTRACT(MONTH FROM `app01_user`.`join_time`) = 9
    
    • 1
    • 2
    • 3

    方式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',
           },
       }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    ORM外键字段创建

    1.外键字段关系之一对多

    models.ForeignKey()
    
    • 1

    ORM中外键字段建在多的一方 ;
    会自动添加_id后缀。

    2.外键字段关系之多对多

    models.ManyToManyField()
    
    • 1

    ORM中有三种创建多对多字段的方式:

    • 方式1:直接在查询频率较高的表中填写字段即可 自动创建第三张关系表
    • 方式2:自己创建第三张关系表
    • 方式3:自己创建第三张关系表 但是还是要orm多对多字段做关联

    3.外键字段关系之一对一

    models.OneToOneField()
    
    • 1

    ORM中外键字段建在查询频率较高的表中 ;
    会自动添加_id后缀。

    4.特别补充:

    • django1.X 针对 models.ForeignKey() models.OneToOneField()不需要on_delete参数的;
    • django2.X 3.X 则需要添加on_delete参数

    5.举个栗子之图书管理系统外键字段之间的关系

    class Book(models.Model):
       title = models.CharField(max_length=32)
       price = models.DecimalField(max_digits=8, decimal_places=2)  # 总共八位,小数点后占两位
       publish_time = models.DateTimeField(auto_now=True)
    
       publish = models.ForeignKey(to='Publish',on_delete=models.CASCADE)
       authors = models.ManyToManyField(to='Author')
    
    class Publish(models.Model):
       name = models.CharField(max_length=32)
       email = models.EmailField()
    
    
    class Author(models.Model):
       name = models.CharField(max_length=32)
       age = models.IntegerField()
       author_detail = >models.OneToOneField(to='AuthorDetail',on_delete=models.CASCADE)
    
    class AuthorDetail(models.Model):
       phone =models.BigIntegerField()
       addr = models.CharField(max_length=255)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    外键字段数据操作

    1.针对models.ForeignKey(to=‘Publish’, on_delete=models.CASCADE)外键添加方式。

    方式1直接给实际字段添加关联数据值-------publish_id = 1
    
    models.Book.objects.create(title='python从入门到放弃',price='29800.88',publish_id=1)
    
    • 1
    • 2
    • 3
    方式2间接使用外键虚拟字段添加数据对象 --------publish=publish_obj
    
    publish_obj = models.Publish.objects.filter(pk=2).first()
       models.Book.objects.create(title='django从入门到入土',price=19888.80,publish=publish_obj)
    
    • 1
    • 2
    • 3
    • 4

    2.针对models.OneToOneField(to=‘AuthorDetail’, on_delete=models.CASCADE)外键添加方式。

    方式1直接给实际字段添加关联数据值--------author_detail_id = 1
    
    • 1
    	方式2间接使用外键虚拟字段添加数据对象--------author_detail=authorDetail_obj
    
    • 1

    3.针对多对多models.ManyToManyField(to=‘Author’)添加外键方式。

    add()
       	添加数据  括号内即可以填写数字值也可以填写数据对象 支持多个
    
    remove()
       删除数据  括号内即可以填写数字值也可以填写数据对象 支持多个
    
    set()
    	修改数据  括号内必须是可迭代对象 
    
    clear()
    	清空指定数据  括号内不需要任何参数
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    正反向概念

    1.正反向的概念核心就在于外键字段在谁手上

    • 正向查询
      通过书查询出版社 外键字段在书表中
    • 反向查询
      通过出版社查询书 外键字段不在出版社表中

    ORM跨表查询口诀>>>:正向查询按外键字段 反向查询按表名小写

    2.基于对象的跨表查询(子查询)
    基于对象的正向跨表查询

    • 查询主键为1的书籍对应的出版社(书>>>出版社)
      (1)先根据条件查询数据对象(先查书籍对象)
    book_obj = models.Book.objects.filter(pk=1).first()
    
    • 1

    (2)以对象为基准 思考正反向概念(书查出版社 外键字段在书表中 所以是正向查询)

    print(book_obj.publish)
    
    • 1
    • 查询主键为3的书籍对应的作者(书>>>作者)
      (1)先根据条件查询数据对象(先查书籍对象)
    book_obj = models.Book.objects.filter(pk=3).first()
    
    • 1

    (2)以对象为基准 思考正反向概念(书查作者 外键字段在书表中 所以是正向查询)

    print(book_obj.authors)  # app01.Author.None
    print(book_obj.authors.all())
    
    • 1
    • 2
    • 查询jason的作者详情
      (1)先根据条件查询数据对象
    author_obj = models.Author.objects.filter(name='jason').first()
    
    • 1

    (2)以对象为基准 思考正反向概念

    print(author_obj.author_detail)
    
    • 1

    基于对象的反向跨表查询

    • 查询南方出版社出版的书籍
      (1)先拿出版社对象
    publish_obj = models.Publish.objects.filter(name='南方出版社').first()
    
    • 1

    (2)思考正反向

    # print(publish_obj.book)
    # print(publish_obj.book_set)  # app01.Book.None
    print(publish_obj.book_set.all())
    
    • 1
    • 2
    • 3
    • 查询jason写过的书
      (1)先拿作者对象
    author_obj = models.Author.objects.filter(name='jason').first()
    
    • 1

    (2)思考正反向

    # print(author_obj.book)
    # print(author_obj.book_set)  # app01.Book.None
    print(author_obj.book_set.all())
    
    • 1
    • 2
    • 3
    • 查询电话是110的作者
      (1)先拿作者详情对象
    author_detail_obj = models.AuthorDetail.objects.filter(phone=110).first()
    
    • 1

    (2)思考正反向

    print(author_detail_obj.author)
    
    • 1

    2.基于双下划线的跨表查询(连表操作)
    基于双下划线的正向跨表查询

    • 查询主键为1的书籍对应的出版社名称及书名
    res = models.Book.objects.filter(pk=1).values('publish__name','title')
    print(res)
    
    • 1
    • 2
    • 查询主键为3的书籍对应的作者姓名及书名
    res = models.Book.objects.filter(pk=3).values('authors__name', 'title')
    print(res)
    
    • 1
    • 2
    • 查询jason的作者的电话号码和地址
    res = models.Author.objects.filter(name='jason').values('author_detail__phone','author_detail__addr')
    print(res)
    
    • 1
    • 2

    基于双下划线的反向跨表查询

    • 查询南方出版社出版的书籍名称和价格
    res = models.Publish.objects.filter(name='南方出版社').values('book__title','book__price')
    # print(res)
    
    • 1
    • 2
    • 查询jason写过的书的名称和日期
    res = models.Author.objects.filter(name='jason').values('book__title','book__publish_time')
    # print(res)
    
    • 1
    • 2
    • 查询电话是110的作者姓名和年龄
    res = models.AuthorDetail.objects.filter(phone=110).values('author__name','author__age')
    print(res)
    
    • 1
    • 2

    研究ORM跨表本质(需要用到三张表)

    • 查询主键为1的书籍对应的作者电话号码
    res = models.Book.objects.filter(pk=1).values('authors__author_detail__phone')
       print(res)
    
    • 1
    • 2
  • 相关阅读:
    CSS media属性的使用-兼容不同设备不同屏幕宽度的写法
    MySQL数据库基础回顾与复习
    企业安全生产隐患排查治理系统
    MySQL锁,锁的到底是什么?
    【C语言进阶】动态内存管理及柔性数组
    FreeRTOS笔记 - 二(正点原子)
    CrossOver22试用期到了如何免费使用?
    Tomcat运行常见问题
    第十周周报
    Zookeeper Watcher机制--数据变更通知
  • 原文地址:https://blog.csdn.net/DiligentGG/article/details/126715581