多表外键字段增删改查、正反向查询技巧、基于对象的跨表查询、基于双下划线的跨表查询、F与Q查询

昨日内容回顾

  • 模板标签
{{ 使用变量的时候 }}

{% 跟逻辑相关的时候 %}

# 模板标签也会自动补全
  • 模板继承
# 使用场景:在混合开发的项目中

{% extends 'home.html' %}  # 导入指定文件内全部代码内容


{% block content %}
{% endblock %}


{% block css %}
{% endblock %}


{% block js %}
{% endblock %}


# 模板导入
'''被导入的页面一般是一个局部页面''''
{% include 'menu.html' %}
  • 测试环境的准备
直接cv manage.py中的前4行,放到tests.py中,在加两句话:
import django
django.setup()

# 测试环境的代码不一定非要放在tests.py中, 放在任意目录下即可
  • ORM的常用查询方法
1. all
2. first()
3. last()
4. filter => where
5. get
6. values  # 返回的结果是列表套字典
7. values_list  # 列表套元组
8. order_by()  # 默认是升序,字段前面加负号-就是降序,也支持多个字段排序
9. distinct  # 不能加主键,有unique的也没有意义
10. exclude 
11. exists
12. reverse

# 补充索引的分类:
	1. 索引加快查询速度
	2. 分类:
		2.1 主键索引
		2.2 唯一索引
		2.3 普通索引  create index()
		2.4 联合索引,组合索引 
			a b c  # index(a, b, c)
			走索引的情况(最左匹配原则):a,  ab, abc 
			不走的情况:b, c bc, ac
			eg:
				where b=1 and c=2
			# explain select *from t1
  • 基于双下划线的查询
1. gt gte
2. lt lte
3. range => between and
4. in
5. containers
6. startwith
7. endswith
8. __year
9. __month

今日内容概要

  • 外键字段的增删改查
  • 正反向查询的概念
  • 基于对象的跨表查询(子查询)
  • 基于双下划綫的跨表查询(连表操作)
  • F与Q查询
  • 聚合查询和分组查询

内容详细

1. 数据表准备

# 前期数据表准备
# 以图书 出版社 作者 作者详情表为例


# 1.在models.py文件中创建表:
# 书籍表
class Book(models.Model):
    title = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=8,decimal_places=2)
    '''
    auto_now=False,
        如果设置为True, 在更新当前记录的数据时候,会自动更新时间
    auto_now_add=False,
        如果设置为True,当插入数据的时候,会把当前时间自动添加进去
    '''
    # publish_time = models.DateField
    publish_time = models.DateTimeField(auto_now=True)
    publish = models.ForeignKey(to='Publish')
    authors = models.ManyToManyField(to='Author')

    # 查询时返回表头
    def __str__(self):
        return self.title
    
# 出版社表
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)
    author_detail = models.OneToOneField(to='AuthorDetail')

    # 查询时返回名称
    def __str__(self):
        return self.name
    
# 作者详情表
class AuthorDetail(models.Model):
    phone = models.CharField(max_length=32)
  

# 2.在任一init.py文件中写入:
import pymysql
pymysql.install_as_MySQLdb()


# 3.在settings.py文件中 更改配置连接数据库:
DATABASES = {
    # 'default': {
    #     'ENGINE': 'django.db.backends.sqlite3',
    #     'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    # },
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'day07',  # 数据库名 自己先用 navicat创建
        'HOST': '127.0.0.1',
        'PORT': 3306,
        'USER': 'root',
        'PASSWORD': '123',
        'CHARSET': 'utf8'
    }
}


# 4.在test.py文件中创建测试环境:
import os

if __name__ == "__main__":
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite6.settings")
    import django
    django.setup()
    from app01 import models

    # 代码写在此处下面

image

2. 外键字段的增删改查

# 先自定义出版社 再添加图书
# 在 test.py文件中测试:
import os

if __name__ == "__main__":
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite6.settings")
    import django
    django.setup()
    from app01 import models

    # 代码写在此处下面
    # 针对一对多 一对一
    # 1.增加数据 增加一本书
    # 方式一
    # models.Book.objects.create(title='西游记', price=100, publish_time='2022.3.3', publish_id=1)
    # 方式二
    # 先查询出你要添加的出版社对象
    # publish_obj = models.Publish.objects.filter(pk=2).first()
    # models.Book.objects.create(title='西游记1', price=111, publish_time='2022-02-01', publish=publish_obj)

    # 2.改
    # 将主键id为1的出版社id改为2
    # 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  # 代表已经到第三张表了
    # 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, author_obj2)

    # 2.改
    # book_obj.authors.set([3, 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, author_obj2])

    # 3.删除
    # book_obj = models.Book.objects.filter(pk=2).first()
    # book_obj.authors.remove(1)
    # book_obj.authors.remove(1,2)
    # author_obj = models.Author.objects.filter(pk=1).first()
    # author_obj1 = models.Author.objects.filter(pk=2).first()
    # book_obj.authors.remove(author_obj)
    # book_obj.authors.remove(author_obj, author_obj1)
    """
    remove
        在第三张关系表中删除数据
            括号内既可以传主键字段也可以传数据对象 并且都支持传多个
    """
    # 清空
    # book_obj = models.Book.objects.filter(pk=2).first()
    # book_obj.authors.clear()  # 清空当前书籍与作者的所有绑定关系
    """
    clear
        在第三张关系表中清空数据
            括号内无需传值
    """

image

image

image

3. 正反向查询

# 正向查询
	书籍对象查出版社对象 外键字段在书表中   # 正向查询
	书籍对象查作者对象 外键字段在书表中  # 正向查询
	作者对象查作者详情 外键字段在作者中  # 正向查询
    
# 反向查询
	出版社查书籍对象 外键字段不在出版社表中  # 反向查询
	作者查书籍对象 外键字段不在作者表中  # 反向查询
	作者详情查作者 外键字段不在作者详情表中  # 反向查询 
	'''
	外键字段在我手上,我查你就是正向
	外键字段不再我手上,我查你就是反向
	'''

# 口诀:
	正向查询按外键字段 ...
	反向查询按表名小写 或 +_set ...

4. 基于对象的跨表查询(子查询)

"""将一条SQL语句的查询结果当做另外一条SQL语句的查询条件"""

'''基于对象的跨表查询'''
# 在 test.py文件中测试:

    # 1.查询书籍主键为1的出版社
    # 书 >>> 出版社  >>> 正向
    # book_obj = models.Book.objects.filter(pk=1).first()
    # print(book_obj)  # 西游记
    # print(book_obj.publish)  # Publish object 代表的是出版社对象
    # print(book_obj.publish.name)  # 北京大学出版社
    # print(book_obj.publish.addr)  # 北京

    # 2.查询书籍主键位1的作者
    # book >>> author >>> 正向
    # book_obj = models.Book.objects.filter(pk=1).first()
    # print(book_obj.authors)  # app01.Author.None
    # print(book_obj.authors.all())  # <QuerySet [<Author: beijing>, <Author: qinghua>]>
    # for author_obj in book_obj.authors.all():
    #     print(author_obj.name)  # beijing qinghua

    # 3.查询 qinghua 的手机号
    # 作者 >>> 作者详情 >>> 正向
    # author_obj = models.Author.objects.filter(name='qinghua').first()
    # print(author_obj.author_detail)  # AuthorDetail object 结果时对象
    # print(author_obj.author_detail.phone)  # 120

    # 4.查询武汉出版社出版的书籍
    # 出版社查书 >>> 反向
    # publish_obj = models.Publish.objects.filter(name='武汉大学出版社').first()
    # print(publish_obj.book_set)  # app01.Book.None
    # print(publish_obj.book_set.all())  # <QuerySet [<Book: 红楼梦>]>
    # for book_obj in publish_obj.book_set.all():
    #     print(book_obj.title)  # 红楼梦

    # 5.查询 qinghua 写过的书
    # 作者查书  >>> 反向
    # author_obj = models.Author.objects.filter(name='qinghua').first()
    # print(author_obj.book_set.all())  # <QuerySet [<Book: 西游记1>]>

    # 6.查询手机号是120的作者姓名
    # 作者详情查作者信息  >>> 反向
    # author_detail_obj = models.AuthorDetail.objects.filter(phone=120).first()
    # print(author_detail_obj.author)  # qinghua


'''
总结:
	反向查询只要查询出的结果可能有多个的时候,都要加上 表名_set.all()
	如果查询出来的结果是一个,就不用加_set,直接使用表名小写
'''

image

image

5. 基于双下划线的跨表查询

"""正反向查询的概念同样适用"""
# 在 test.py文件中测试:

    # 1.查询书籍主键为1的出版社名称与书籍名称
    # 正向
    # res = models.Book.objects.filter(pk=1).values('title', 'publish__name')
    # print(res)  # <QuerySet [{'title': '西游记', 'publish__name': '北京大学出版社'}]>

    # 2.查询书籍主键位1的作者
    # 正向
    # res = models.Book.objects.filter(pk=1).values('authors__name')
    # print(res)  # <QuerySet [{'authors__name': 'beijing'}]>

    # 3.查询作者 qinghua 的手机号
    # 正向
    # res = models.Author.objects.filter(name='qinghua').values('author_detail__phone')
    # print(res)  # <QuerySet [{'author_detail__phone': '120'}]>

    # 4.查询 武汉大学出版社 出版的书籍名称
    # 反向
    # res = models.Publish.objects.filter(name='武汉大学出版社').values('book__title')
    # print(res)  # <QuerySet [{'book__title': '红楼梦'}]>

    # 5.查询 qinghua 写过的书
    # 反向
    # res = models.Author.objects.filter(name='qinghua').values('book__title')
    # print(res)  # <QuerySet [{'book__title': '西游记1'}]>

    # 6.查询手机号是120的作者姓名
    # 反向
    # res = models.AuthorDetail.objects.filter(phone=120).values('author__name')
    # print(res)  # <QuerySet [{'author__name': 'qinghua'}]>

    # 7.查询书籍主键位1的作者的手机号
    # 正向
    # book   author   author_detail
    # res = models.Book.objects.filter(pk=1).values('authors__author_detail__phone')
    # print(res)  # <QuerySet [{'authors__author_detail__phone': '110'}]>

6. F查询和Q查询

# F查询
	可以拿到数据库中原有的数据
     
    from django.db.models import F
    ''' F查询默认是对数字类型的'''
    # 1.把书籍的价格在原来的基础之上加100元
    # SQL语句:
		# update book set price = price + 100 where id=1;
    '''
    一般来说,跟数据相关的模块要么在django.db,要么在django.db.models
    '''
    # models.Book.objects.update(price=F('price')+100)
        
    # 2.F查询对 字符类型的
    from django.db.models.functions import Concat
    from django.db.models import Value
    # models.Book.objects.update(title=Concat(F('title'), Value('南京出版社')))


# Q查询

    # 查询书籍价格大于等于300的或者id=1的数据
    # sql: select * from t where price >= 300 or id=1
    # orm:
    from django.db.models import Q
    # res = models.Book.objects.filter(Q(price__gte=300), Q(id=1))  # 逗号分隔,是and关系
    # res = models.Book.objects.filter(Q(price__gte=300) | Q(id=1))  # |分隔,是or关系
    # res = models.Book.objects.filter(~Q(price__gte=300) | ~Q(id=1))  # ~分隔,取反
    # print(res)

image

posted @   Deity_JGX  阅读(66)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
点击右上角即可分享
微信分享提示