文章目录
Django ORM语法进阶
单表操作
- 在操作前可以先配置好测试环境,方便对数据库进行测试
1. 在tests.py文件中写入下面代码 (任意新建一个文件也行)
import os
if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "djangoProject.settings")
import django
django.setup()
# 所有的代码都必须等待环境准备完毕之后才能书写
from app01 import models
models.User.objects.all()
- django自带的sqlite3数据库对日期格式不是很敏感 处理的时候容易出错,所以我们用mysql数据库
ORM创建时间日期代码有
models.DateFiled()
models.DateTimeFiled()
参数解析:
auto_now : 每次操作数据的时候,该字段会自动更新当前时间
auto_now_add : 创建数据的时候,会自动将当前时间记录下来,只有人为修改才会改变
- 增
方式1:
res = models.表名.objects.create(字段名1=值1,字段名2=值2,...)
方式2:
res = models.表名(字段名1=值1,字段名2=值2,...)
res.save()
- 删
res = models.表名.objects.filter(字段名=值).delete()
建议使用
res = models.表名.objects.filter(pk=值).delete()
pk会自动查找当前表的主键字段 指代的就是当前表的主键字段 值为主键字段的值
res 返回值返回的是你删除的表名和删除了几行
- 改
方式1:
res = models.表名.objects.filter(字段名=值).updata(字段名1=值1,字段名2=值2,...)
方式2:
res = models.表名.objects.get(字段名=值)
res.字段名1 = 值1
res.字段名2 = 值2
res.save()
'''
get方法返回的值就是当前数据对象
由于一旦数据不存在该方法会直接报错,而filter则不会,不推荐使用get
'''
必知必会13条
参数 | 解析 |
---|---|
all() | 查询所有数据 |
filter() | 带有过滤条件查询 |
get() | 直接拿数据对象 但是条件不存在就直接报错 |
first() | 拿第一个 |
last() | 拿最后一个 |
values() | 获取值,可以指定字段 |
values_list() | 获取值,可以指定字段 数据格式同上面不一样 |
distinct() | 去重 |
order_by(‘age’) | 排序,默认升序,加(-):(‘-age’)就降序 |
reverse() | 反转,前提是数据已经排过序 |
count() | 统计当前数据个数 |
exclude() | 排除在外 |
exists() | 判断是否存在,返回值是布尔值 |
查看内部sql语句的方式
# 方式1
res = models.User.objects.values_list('name','age') # <QuerySet [('jason', 18), ('egonPPP', 84)]>
print(res.query)
只有queryset对象才能够点击query查看内部的sql语句
# 方式2:所有的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. __gt 大于
# 年龄大于35岁的数据
res = models.User.objects.filter(age__gt=35)
2. __lt 小于
# 年龄小于35岁的数据
res = models.User.objects.filter(age__lt=35)
3. __gte 大于等于 __lte 小于等于
4. __in 存在
# 年龄是18 或者 32 或者40
res = models.User.objects.filter(age__in=[18,32,40])
5. __range
# 年龄在18到40岁之间的 首尾都要
res = models.User.objects.filter(age__range=[18,40])
6. __contains # 模糊查询
# 查询出名字里面含有s的数据 模糊查询 忽略大小写
res = models.User.objects.filter(name__contains='s')
7. __icontains # 忽略大小写
res = models.User.objects.filter(name__icontains='p')
8. __startswith 和 __endswith 以某某开头和以某某结尾
9. __month,__year,__day...
获取月份 年份 天 ...
# 查询出注册时间是 2020 1月
# res = models.User.objects.filter(register_time__month='1')
# res = models.User.objects.filter(register_time__year='2020')
一对多外键增删查改
- 增
1 直接写实际字段 publish_id = id
model.Book.objects.create(title='论语',price=899.23,publish_id=1)
2 虚拟字段 publish_id = 对象
publish_obj = models.Publish.objects.filter(pk=2).first()
models.Book.objects.create(title='红楼梦',price=666.23,publish=publish_obj
- 删
models.Publish.objects.filter(pk=1).delete() # 级联删除
- 修改
models.Book.objects.filter(pk=1).update(publish_id=2) # publish_id也可以对象
多对多外键增删查改
- 多对多外键关系会自动建立第三张表,而在orm中是无法直接通过 点 的方式点到第三张表,多对多需要先进行如下操作
1. 先获取对象
book_obj = models.Book.objects.filter(pk=1).first()
2. 通过 author = models.ManyToManyField('Author') 来获取第三张表
book_obj.author
- 增.add
book_obj.author.add(1,2) # 书籍id为1的书籍绑定主键为1 和 2 的作者
author_obj1 = models.Author.objects.filter(pk=2).first()
book_obj.authors.add(author_obj)
"""
add给第三张关系表添加数据
括号内既可以传数字也可以传对象 并且都支持多个
"""
- 删.remove
book_obj.authors.remove(2)
"""
remove
括号内既可以传数字也可以传对象 并且都支持多个
"""
- 修改
book_obj.authors.set([1,2]) # 括号内必须给一个可迭代对象
book_obj.authors.set([author_obj,author_obj1]) # 括号内必须给一个可迭代对象
"""
set
括号内必须传一个可迭代对象,该对象内既可以数字也可以对象 并且都支持多个
"""
- 清空
book_obj.authors.clear() # 不需要任何参数 会清空第三张关系表中某个书籍与作者的绑定关系
正反向概念
外键字段在手上那么,通过外键查另一种表数据就是正向
外键字段如果不在手上,通过外键查另一种表数就是反向
正向查询按字段
反向查询按表名小写
多表查询案例
子查询(基于对象的跨表查询)
- 查询书籍主键为1的出版社
book_obj = models.Book.objects.filter(pk=1).first()
res = book_obj.publish
print(res)
# 正向查询
- 查询书籍主键为2的作者
book_obj = models.Book.objects.filter(pk=2).first()
res = book_obj.author # app01.Author.None
print(res.all()) # <QuerySet [<Author: Author object>]>
# 正向查询
- 查询作者张三的电话号码
author_obj = models.Author.objects.filter(name='张三').first()
res = author_obj.author_detail.iphone
print(res)
# 正向查询
- 查询出版社是东方出版社的书
publish_obj = models.Publish.objects.filter(name='东方出版社').all()
res = publish_obj.book_set # app01.Book.None
print(res.all()) # <QuerySet [<Book: Book object>]>
# 反向查询
- 查询作者是李四写过的书
author_obj = models.Author.objects.filter(name='李四').first()
res = author_obj.book_set
print(res.all())
# 反向查询
- 查询手机号是 110 的作者姓名
author_d_obj = models.AuthorDetail.objects.filter(iphone=110).first()
res = author_d_obj.author
print(res.name)
# 反向查询
总结:
正向查询时
- 当结果可能由多个的时候需要加.all()
- 当结果是一个的时候直接拿到数据对象
反向查询时
- 当查询结果可以有多个的时候 必须要加上_set.all()
- 当结果只有一个的时候 不需要加_set.all()
联表查询(基于双下划线的跨表查询)
使用.values 和 .values_list 联表查询。 默认是全联表,不能为空。只会查询外键字段有值的数据,不会查询外键字段为空的数据。
解决方案: 在 orm 里面加上 null=true,查询就会变成左联表
- 查询张三的手机号
res = models.Author.objects.filter(name='张三').values('author_detail__iphone')
print(res) # <QuerySet [{'author_detail__iphone': 123456789098}]>
# 正向
res = models.AuthorDetail.objects.filter(author__name='张三').values('iphone')
print(res)
# 反向
- 查询书籍主键为1的出版社名称和书的名称
res = models.Book.objects.filter(pk=1).values('name','publish__name')
print(res) <QuerySet [{'name': '论语', 'publish__name': '东方出版社'}]>
# 正向
res = models.Publish.objects.filter(book__id=1).values('book__name','name')
print(res)
# 反向
- 查询书籍主键为1的作者姓名
res = models.Book.objects.filter(pk=1).values('author__name')
print(res)
# 正向
res = models.Author.objects.filter(book__id=1).values('name')
print(res)
# 反向
- 查询书籍主键是1的作者的手机号
res = models.Book.objects.filter(pk=1).values('author__author_detail__iphone')
print(res)
# 正向
res = models.AuthorDetail.objects.filter(author__book__id=1).values('iphone')
print(res)
# 反向