ORM就是为了让不会数据库操作的python程序员也能够操作数据库处理数据,而处理数据无非就是对数据的增、删、改、查,因此ORM给我们提供了各种操作数据的关键字
先创建一张表用于举例
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)
1.模型层测试环境准备
方式一:在任意空的py文件中准备环境
import os def main(): os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'day59.settings') import django django.setup() if __name__ == '__main__': main()
2.常见关键字
create():创建数据 返回值就是当前创建的数据对象
update():更新数据
delete():删除数据
'添加数据' models.User.objects.create('小明','18') models.User.objects.create('小强','26') models.User.objects.create('小红','38') models.User.objects.create('小兰','66') '修改id为2的年龄' models.User.objects.filter(pk=2).update(age=88) '删除id为3的数据' models.User.objects.filter(pk=3).delete()
常见的13个查询关键字:
filter():返回值是一个QuerySet(可以看成是列表套数据对象)
res = models.User.objects.filter(name='小明', age=18) ''' 括号内可以填写多个条件 逗号分开默认是and关系 括号内不写查询条件 默认查询所有 '''
all():查询所有数据 返回值是一个QuerySet(可以看成是列表套数据对象)
res = models.User.objects.all() print(res[1]) for i in res: print(i) ''' 可以索引获取每个数据对象 也可以用for循环获取 '''
first():获取Queryset中第一个数据对象 如果是空则返回None
res = models.User.objects.filter(name="小明").first() print(res)
last():获取Queryset中最后一个数据对象 如果是空则返回None
res = models.User.objects.filter(name="小明").last() print(res)
get():直接根据条件查询具体的数据对象 如果条件不存在直接报错(不推荐使用)
res = models.User.objects.get(pk=999) print(res) ''' 显然没有id为999的值所以会直接报错 更推荐下面这种方式 ''' res = models.User.objects.filter(pk=999).first() print(res) # 不存在返回None
values():指定查询字段 结果是Queryset(可以看成是列表套字典数据)
res = models.User.objects.all().values('name', 'age') print(res) ''' 获取别中所有数据的'name','age'字段数据 '''
values_list():指定查询字段 结果是Queryset(可以看成是列表套元组数据)
res = models.User.objects.values_list('name','join_time') print(res)
order_by():指定字段排序 默认是升序 在字段前加负号则为降序 并且支持多个字段排序
res = models.User.objects.order_by('age') # 按年龄升序 res = models.User.objects.order_by('-age') # 按年龄降序 res = models.User.objects.order_by('age','-join_time') # 先按年龄升序有相同的年龄再按创建时间降序
count():统计ORM查询之后结果集中的数据格式
res = models.User.object.all().count()
distinct():针对重复的数据进行去重 (注意数据对象中的主键)
res = models.User.objects.values('name','join_time').distinct() print(res) ''' 避免主键因为主键肯定是不重复的数据 '''
exclude():针对括号内的条件取反进行数据查询(QuerySet可以看成是列表套数据对象)
res = models.User.objects.exclude(pk=1) print(res) ''' 查询除id是1以为的所有数据 '''
reverse():针对已经排序了的结果集做颠倒
res = models.User.objects.all().order_by('age').reverse() print(res) ''' 将按年龄升序完后的数据再取个反,倒叙一下 '''
existe():判断查询结果是否有数据, 返回布尔值(几乎所有数据都已自带布尔值了)
res = models.User.objects.filter(pk=999).exists() print(res) ''' 判断查询结果 True/False '''
raw():执行SQL语句
res = models.User.objects.raw('select * from app01_user') print(res) ''' 注意要用生成的app01_user表 也可以用另一种方法:在配置文件中加 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.比较运算符
''' 字段__gt 大于 字段__lt 小于 字段__gte 大于等于 字段__lte 小于等于 ''' # 举例: res = models.User.objects.filter(age__gt=20) # 查询年龄大于20的数据,换成__gte则是查询小于等于 res1 = models.User.objects.fileter(age__lt=20) # 查询年龄小于20的数据,换成__lte则是查询小于等于
2.日期处理
''' 字段__year 年 字段__month 月 字段__day 日 ''' res = models.User.objects.filter(join_time__year=2022) # 查询创建年份是2022年的数据 res = models.User.objects.filter(join_time__month=9) # 查询创建月份是9月的数据 res = models.User.objects.filter(join_time__day=5) # 查询创建日子是5号的数据
3.其它补充
''' 字段__in 在什么里 字段__range 数字范围 字段__contains 模糊查询(不忽略大小写) 字段__icontains 模糊查询(忽略大小写) ''' # 举例 res = models.User.objects.filter(name__in =['小明','小兰']) # 查询姓名是小明或者小兰的数据 res = models.User.objects.filter(age__range=(38, 88)) # 查询年龄在38到88之间的数据(包含首尾) res = models.User.objects.filter(name__icontains='H') # 查询名字中带有字母H的忽略大小写包含h的也行 res = models.User.objects.filter(name__contains='H') # 查询名字中带有字母H只能是大写字母H
方式一:
如果结果是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', }, } }
1.一对多
ORM中外键字段建在多的一方 会自动添加_id后缀
models.ForeignKey()
2.多对多
ORM中有三种创建多对多字段多方式
models.ManyToManyField() ''' 方式1:直接在查询频率较高的表中填写字段即可 自动创建第三张关系表 方式2:自己创建第三张关系表 方式3:自己创建第三张关系表 但是还是要ORM多对多字段做关联 '''
3.一对一
ORM中外键字段建在查询频率较高的表中 自动添加__id后缀
models.OneToOneField()
django1.x 针对 models.ForeignKey() 、models.OneToOneField() 不需要on_delete
django2.x 3.x 则需要添加on_delete参数
4.创建表格
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') def __str__(self): return '书籍对象:%s' % self.title class Publish(models.Model): name = models.CharField(max_length=32) email = models.EmailField() def __str__(self): return '出版社对象:%s' % self.name class Author(models.Model): name = models.CharField(max_length=32) age = models.IntegerField() author_detail = models.OneToOneField(to='AuthorDetail', on_delete=models.CASCADE) def __str__(self): return '作者对象:%s' % self.name class AuthorDetail(models.Model): phone = models.BigIntegerField() addr = models.CharField(max_length=255) def __str__(self): return '作者详情对象:%s' % str(self.phone)
4.2.外键字段数据操作
models.ForeignKey?(to='Publish', on_delete=models.CASCADE) ''' 方式一:直接给实际字典添加关联数据值 publish_id = 1 方式二:间接使用外键虚拟字段添加数据对象 publish = publish_obj ''' models.OneToOneField(to='AuthorDetail', on_delete=models.CASCADE) ''' 方式一:直接给实际字段添加关联数据值 author_detail_id = 1 方式二:间接使用外键虚拟字段添加数据对象 author_detail = authorDetail_obj ''' models.ManyToManyField(to='Author')
add():添加数据 括号内可以填写数字值也可以填写数据对象 支持多个
remove():删除数据 括号内即可以填写数字值也可以填写数据对象 支持多个
set():修改数据 括号内必须是可迭代对象
clear():清空指定数据 括号内不需要任何参数
1.正反向概念
正反向的概念核心在于外键字段在谁手上
正向查询
通过书查询出版社 外键字段在书表中
反向查询
通过出版社查询书 外键字段不在出版社表中
ps:ORM多表查询口诀>>>:正向查询按外键字段 反向查询按表名小写(_set)
2.基于对象的跨表查询(子查询)
举例题目理解正向查询与反向查询
# 查询主键为1的书籍对应的出版社 ''' 1.1 先根据条件查询数据对象 1.2 以对象为基准 考虑是正向还是反向 在通过口诀(正向) ''' book_obj = models.Book.objects.filter(pk=1).first() print(book_obj.publish) # 查询出版社出版的书籍 ''' 2.1 先根据条件查询数据对象 2.2 一样思考是正向还是反向 再给予口诀(反向) ''' publish_obj = models.Publish.objects.filter(name ='出版社') print(publish_obj.book_set.all())
ps:反向查询时表名小写后还需加(_set)此时获取到的是 app01.Book.None 所以还要加上all()
3.基于双下划线的跨表查询(连表操作)
举例题目理解基于双下划线的正向查询与反向查询
# 查询主键为1的书籍对应的出版社及书名 ''' 1.1 根据条件查询数据对象 1.2 以对象为基准加关键字 values获取另一张表数据 (正向) ''' res = models.Book.objects.filter(pk=1).values('publish__name','title') # 查询出版社出版的书籍名称和价格 ''' 2.1 根据条件查询数据对象 2.2 以对象为基准加关键字 values获取另一张表数据 (反向) ''' res = models.Publish.objects.filter(name='出版社').values('book_title','book_price')