Day 59 django ROM 多表查询

Day 59 django ROM 多表查询

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

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

django切换MySQL数据库

django 1.x 跟适合使用pymysql
import pymysql
pymysql.install_as_MySQLdb()

django2.X 3.X 4.X 适合用mysqlclient
pip install mysqlclient

1.1、定义模型类

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.DateTimeField(auto_now_add=True)

日子其字段重要参数
auto_now:每次操作数据并保存都会自动更新当前时间
auto_now_add:只在创建数据的那一刻自动获取当前时间 之后如果不人为更改则不变

执行数据迁移命令

python3.7 manage.py makemigration
python3.7 manage.py migrate

1.2、模型测试环境准备

方式一:
在任意py文件中准备环境

import os


def main():
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'Day59.settings')
    import django
    django.setup()
    from app01 import models
    print(models.User.objects.filter())


if __name__ == '__main__':
    main()

方式二:
pycharm 提供的测试环境

python console 命令行测试环境

2、ORM查询关键字

当需要查询数据主键字段值的时候 可以使用pk忽略掉数据字段真正的名字

在模型类中可以定义一个__str__ 方法 便于后续数据对象被打印展示的是查看方便

Queryset中如果时列表套对象 那么直接for循环和索引取值但是 索引不支持负数

虽然queryset中如果是列表套对象 那么直接for循环和索引取值但是索引取值不支持负数

虽然queryset 支持索引 但是当queryset 没有数据的时候 索引会报错 推荐使用first

创建对象
create()
delete()
update()

res=models.User.objects.create(name='jason',age=38)
    print(res.name)  # 查看 name
    print(res.age)  #查看age
    print(res.join_time)  #查看 创建时间
    print(res.pk)  #查看主键  不需要知道主键字段名 通用pk

通过.save()

res = models.User(name='kk',age='22')
res.save()

2.1、常用的查询关键字

查看数据
all()

# 获取表中 所有数据
res = models.User.objects.all()

通过.first/last() 获取 对象 当对象为空时 返回None

#获取QuerySet列表套对象
res = models.User.objects.filter(name='kk').first()  #通过点first 获取第一个数据对象
print(res)  获取

get()
直接根据条件查询具体的数据对象 但是条件不存在直接报错 不推荐使用

res=models.User.objects.get(pk=5)

拿一些指定字段 下数据
vlaues()

res = models.User.objects.values('name','join_time')
 print(res) #获取的结果 是列表套字典

values_list()

res = models.User.objects.values_list('name','join_time')
print(res)
# 获取的结果是列表套元组 

指定字段排序
order_by()

res = models.User.objects.order_by('age','name')
print(res)

统计结果集中的个数
统计ORM查询之后结果集中的数据个数
count()

res = models.User.objects.all().count()
print(res)

**去重 **
针对重复的数据进行去重 一定要注意数据对象中的主键
distinct()

res = models.User.objects.values('name','age').distinct() # 要用 values 指定查看到的数据 进行去重 用all()有主键不行
print(res)

取反查询
针对括号内的条件取反进行数据查询 QuerSet(可以看成是列表套数据对象)
exclude()

res = models.User.objects.exclude(age__gt=20)
print(res)

对排了序的结果取反
针对已经排了序的结果做颠倒
reverse()

res = models.User.objects.order_by('age').reverse()
print(res)

**判断结果是否有数据 **
返回的是bool值
exists

执行SQL语句
raw()

借助于模块

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()

2.2、双下划线的查询

比较运算符

res = models.User.objects.filter(age__gt=20)
print(res)

字段__gt  	大于
字段__lt		小于
字段__gte		大于等于
字段__lte		小于等于

成员运算

字段__in=['jason','toney','kk']

范围查询(数字)
顾头顾尾

res = models.User.objects.filter(age__range=(20,25))
print(res)

字段__range

模糊查询

res = models.User.objects.filter(name__contains='j')
print(res)
字段__contains   不忽略大小写
字段__icontains  忽略大小写

日期处理

res = models.User.objects.filter(join_time__year=2022)
print(res)

字段__year
字段__month
字段__day

3、ORM查看底层SQL

方式一:
.query

如果是Queryset对象 那么可以直接点query查看SQL语句

方式二:
配置文件配置 打印所有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',
                },
            }
        }

4、ORM外键字段创建

一对多
ORM 中外键字段建在 多的一方 models.Foreignkey()
会自动添加_id后缀

多对多
ORM中有三种创建多对多 字段的方式 models.ManyToManyField()
方式一:直接在查询平吕较高的表中填写字段 自动创建第三章表
方式二:自己创建第三张关系表
方式三:自己创建第三张关系表 但是还是要orm多对多字段做关联

一对一
ORM中外键字段建在查询频率较高的表中 models.OneToOneField()
会自动添加_id后缀

**django1.X **
针对models.Foreignkey() models.OneToOneField() 不需要 on_deletedjango2.X 3.X 则需要添加on_delete

django2.x 3.X
则需要添加on_delete参数

5、外键字段数据操作

给 给一对多外键字段添加 关联数据值

publish = models.ForeignKey(to='Publish',on_delete=models.CASCADE)

方式一:直接给实际字段添加关联数据值 publish_id = 1
方式二:间接使用外键虚拟字段添加数据对象 publish = publish_obj

给一对一外键字段添加 关联数据值

author_detail = models.OneToOneField(to='AutorDetail',on_delete=models.CASCADE)

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

给多对多 外键 第三张表添加关联数据值

authors = models.ManyToManyField(to='Author')

add()

book_obj=models.Book.objects.filter(pk=2).first()
book_obj.authors.add(3)

#直接填加 关联的对象
book_obj=models.Book.objects.filter(pk=2).first()
author_obj=models.Author.objects.filter(pk=2).first()
book_obj.authors.add(author_obj)

remove()

添加数据 括号内可以填写 关联值 也可以填写 关联对象 支持多个

set()
修改数据 括号内必须是可迭代对象 例如列表 、元组 (也可以放对象 可以放多个)
实际是 删除原来的 那条数据 新增 一个在原来的位置

clear()
将第三张表里 所有跟这个对象的关联 清除(括号内不需要任何参数)

6、正反向概念

正反向的概念核心就在于字段在谁手里

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

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

ORM 块表查询口诀>>> 正向查询按外键字段,反向查询按表名小写(后面 还要跟_set)

7、基于对象的跨表查询(子查询)

查询主键为1的书籍对应的出版社(书>>>出版社)

  1. 先根据条件查询数据对象(先查书籍对象)

    book_obj = models.Book.objects.filter(pk=1).first()
    
  2. 以对象为基准 思考正反向

    print(book_obj.publish)
    

查询主键为3的书籍对应的作者

  1. 先根据条件查询数据对象

    book_obj = models.Book.objects.filter(pk=3).first()
    
  2. 以对象为基准 思考正反向
    出现结果 为None代表 结果不止一个 直接 点all

    print(book_obj.authors.all())
    

查询jason的作者详情

  1. 先根据条件查询数据对象

    authors_obj=models.Author.objects.filter(name='jason').first()
    
  2. 以对象为基准 思考正反向

    print(authors_obj.author_detail)
    

查询 北京出版社出版的书

反向查询多对多 后面 跟_set

  1. 先根据条件查询数据对象

    publish_obj=models.Publish.objects.filter(name='南方出版社').first()
    
  2. 以对象为基准 思考正反向

    #print(publish_obj.book)
    #print(publish_obj.book_set)
    print(publish_obj.book_set.all())
    

查询jason写过的书

  1. 先根据条件查询数据对象

    author_obj = models.Author.objects.filter(name='jason').first()
    
  2. 以对象为基准 思考正反向

    print(author_obj.book_set.all())
    

查询电话是138的作者

  1. 先根据条件查询数据对象

    author_detail_obj = models.AuthorDetail.objects.filter(phone='138').first()
    
  2. 以对象为基准 思考正反向

    print(author_detail_obj.author)
    

8、基于双下划线的跨表查询(连表操作)

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

  1. 查询主键为1的书对应的出版社名称及书名

    res = models.Book.objects.filter(pk=1).values('publish__name','title')
    print(res)
    
  2. 查询主键为3的书籍对应的作者姓名及书名

    res = models.Book.objects.filter(pk=3).values('authors__name','title')
    print(res)
    
  3. 查询jason的作者的电话号码及地址

    res = models.Author.objects.filter(name='jason').values('author_detail__phone','author_detail__addr')
    print(res)
    

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

  1. 查询南方出版社出版的书籍名称和价格

    res = models.Publish.objects.filter(name='南方出版社').values('book__title','book__price')
    print(res)
    
  2. 查询jason写过的书的名称和日期

    res = models.Author.objects.filter(name='jason').values('book__title','book__publish_time')
        print(res)
    
  3. 查询电话是110的作者姓名和年龄

    res = models.AuthorDetail.objects.filter(phone='138').values('author__age','author__name')
        print(res)
    
  4. 查询主键为1的书籍对应的作者电话号码(连续跨表)

    res = models.Book.objects.filter(pk=1).values('authors__author_detail__phone')
    print(res)
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值