六,一:orm查询,新增,删除
目录
单表查询
Django
自带的sqlite3
数据库对日期格式
不是很敏感,处理的时候容易出错
- 数据的增加
"""方式一:"""
res = models.User.objects.create(
username='egon_dsb',
password='dbj123',
gender='female',
age=84,
phone=18677436477,
email='18677436477@163.com',
register_time='2020-5-29'
)
"""方式二:"""
user_obj = models.User(
username='jason_dsb',
password='hecha444',
gender='male',
age=18,
phone=18306477402,
email='23446783@qq.com',
register_time='2020-5-28'
)
user_obj.save()
- 数据的查询
"""
pk:会自动地帮我们找到当前表的主键字段
"""
user_obj = models.User.objects.filter(pk=1).first()
print(user_obj)
"""
当前对象:egon_dsb
"""
- 数据的删除
"""方式一:"""
user_obj = models.User.objects.filter(pk=2).delete()
"""方式二:"""
user_obj = models.User.objects.filter(pk=1).first()
user_obj.delete()
- 数据的更改
"""方式一:"""
user_obj = models.User.objects.filter(pk=3).update(username='jason')
"""方式二:"""
user_obj = models.User.objects.get(pk=3) #返回的是当前额数据对象
user_obj.username = 'jason_DSB'
user_obj.save()
get
方法与filter
方法的区别
当数据对象不存在时,filter方法会返回一个None,而get方法会直接报错,因此推荐使用filter方法。
对比字典的取值,推荐使用get方法,而不使用['键']取值。
常用的单表操作方法
- 查询出所有的数据
"""
<QuerySet [<User: 当前对象:jason_DSB>, <User: 当前对象:egon_dsb>, <User: 当前对象:egon_dsb>, <User: 当前对象:egon_dsb>, <User: 当前对象:tank_dsb>]>
"""
query_set = models.User.objects.all()
for item in query_set:
print(item)
- 带过滤条件的查询
user_obj = models.User.object.filter(pk=7)
- 直接获取数据对象,对象不存在时候报错
user_obj = models.User.object.get(pk=11)
"""
app01.models.DoesNotExist: User matching query does not exist.
"""
- 获取query_set里面的第一个元素对象
user_obj = models.User.objects.all().first()
- 获取query_set里面的最后一个元素对象
user_obj = models.User.objects.all().last()
-
获取指定的数据字段
query_set对象
以列表套字典的形式展示
query_set = models.User.objects.all().values('username','phone')
"""
<QuerySet [{'username': 'jason_DSB', 'phone': 18306477402}, {'username': 'egon_dsb', 'phone': 18677436477}, {'username': 'tank_dsb', 'phone': 13806477412}]>
"""
相当于sql语句
select username,phone from user;
query_set对象
以列表套元组的形式展示
query_set = models.User.objects.all().values_list('username','phone')
"""
<QuerySet [('jason_DSB', 18306477402), ('egon_dsb', 18677436477), ('tank_dsb', 13806477412)]>
"""
查看内部封装的sql语句
:
print(query_set.query)
"""
SELECT `app01_user`.`username`, `app01_user`.`phone` FROM `app01_user`
"""
# 仅适用于queryset对象
- 去重distinct()
query_set = models.User.objects.all().values_list('username','phone').distinct()
# <QuerySet [('jason_DSB', 18306477402), ('egon_dsb', 18677436477), ('tank_dsb', 13806477412)]>
"""
SELECT DISTINCT `app01_user`.`username`, `app01_user`.`phone` FROM `app01_user`
"""
注意:去重一定是一模一样的数据,因此不能忽略主键的作用,所以可以先values('非唯一的字段',...), 然后再distinct()
- 排序 order_by
默认升序排序:
query_set = models.User.objects.all().order_by('age')
降序排序:
query_set = models.User.objects.all().order_by('-age')
或者:
query_set = models.User.objects.all().order_by('age').reverse()
- 反转reverse()
"""
反转的前提是数据已经进行了排序,否则将不做任何操作
"""
query_set = models.User.objects.all().order_by('age').reverse()
- 统计query_set里对象的个数
count = models.User.objects.all().count()
- 将某个对象排除exclude
query_set = models.User.objects.all().exclude(username='tank_dsb')
"""
<QuerySet [<User: 当前对象:jason_DSB>, <User: 当前对象:egon_dsb>]
"""
- 判断对象是否存在exists(),返回一个布尔值
is_exists = models.User.objects.filter(pk=12).exists()
print(is_exists) # False
基本用不到,因为查询数据本身就自带布尔值
测试脚本
当你仅仅只是想测试django某一py文件的内容,可以直接写个测试脚本,脚本可以是应用下的tests.py文件,也可以是自定义的py文件。
# 测试环境准备
"""
需要在py文件的开头导入manage.py的前四句,然后自己在写上两句
"""
import os
import sys
if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "BMS.settings")
import django
django.setup()
# 在此代码块的下面可以测试django里面的单个py文件
# 如:
from app01 import models
is_exists = models.User.objects.filter(pk=12).exists()
print(is_exists)
查询内部sql语句的方式
# 方式一
queryset对象可以直接通过query方法查询
query_set = models.User.objects.all().values_list('username','phone')
print(query_set.query)
"""
SELECT `app01_user`.`username`, `app01_user`.`phone` FROM `app01_user`
"""
# 方式二
所有的SQL语句都能查询
需要到settings.py文件中做如下的配置:
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'console':{
'level':'DEBUG',
'class':'logging.StreamHandler',
},
},
'loggers': {
'django.db.backends': {
'handlers': ['console'],
'propagate': True,
'level':'DEBUG',
},
}
}
models.User.objects.all().values_list('username','phone').first()
"""
(0.003) SELECT @@SQL_AUTO_IS_NULL; args=None
(0.003) SELECT `app01_user`.`username`, `app01_user`.`phone` FROM `app01_user` ORDER BY `app01_user`.`id` ASC LIMIT 1; args=()
"""
双下划线查询
- 查询年龄大于35岁的数据
query_set = models.User.objects.filter(age__gt=35)
<QuerySet [<User: 当前对象:egon_dsb,年龄:84>, <User: 当前对象:kevin,年龄:40>]>
- 查询年龄小于35的数据
query_set = models.User.objects.filter(age__lt=35)
<QuerySet [<User: 当前对象:jason_DSB,年龄:18>, <User: 当前对象:tank_dsb,年龄:18>, <User: 当前对象:surpass,年龄:32>]>
- 查询年龄大于等于35的数据
query_set = models.User.objects.filter(age__gte=35).order_by('age')
<QuerySet [<User: 当前对象:alex_dsb,年龄:35>, <User: 当前对象:kevin,年龄:40>, <User: 当前对象:egon_dsb,年龄:84>]>
- 查询年龄小于等于32的数据
query_set = models.User.objects.filter(age__lte=32).order_by('-age')
<QuerySet [<User: 当前对象:surpass,年龄:32>, <User: 当前对象:jason_DSB,年龄:18>, <User: 当前对象:tank_dsb,年龄:18>]>
- 查询年龄是18,32,40的数据
query_set = models.User.objects.filter(age__in=[18,32,40]).order_by('-age')
<QuerySet [<User: 当前对象:kevin,年龄:40>, <User: 当前对象:surpass,年龄:32>, <User: 当前对象:jason_DSB,年龄:18>, <User: 当前对象:tank_dsb,年龄:18>]>
- 查询年龄在18到40之间的数据(首尾都要)
query_set = models.User.objects.filter(age__range=[18,40]).order_by('-age')
<QuerySet [<User: 当前对象:kevin,年龄:40>, <User: 当前对象:alex_dsb,年龄:35>, <User: 当前对象:surpass,年龄:32>, <User: 当前对象:jason_DSB,年龄:18>, <User: 当前对象:tank_dsb,年龄:18>]>
- 模糊查询,查询名字中带有’s‘的数据
query_set = models.User.objects.filter(username__contains='s').order_by('-age')
"""
<QuerySet [<User: 当前对象:egon_dsb,年龄:84>, <User: 当前对象:alex_dsb,年龄:35>, <User: 当前对象:surpass,年龄:32>, <User: 当前对象:jason_DSB,年龄:18>, <User: 当前对象:tank_dsb,年龄:18>]>
"""
注意:模糊查询默认是区分大小写的,如果要忽略大小写,使用__icontains
query_set = models.User.objects.filter(username__icontains='s').order_by('-age')
"""
<QuerySet [<User: 当前对象:egon_dsb,年龄:84>, <User: 当前对象:alex_dsb,年龄:35>, <User: 当前对象:surpass,年龄:32>, <User: 当前对象:jason_DSB,年龄:18>, <User: 当前对象:tank_dsb,年龄:18>, <User: 当前对象: Steven,年龄:12>]>
"""
- 查询名字以什么开头,以什么结尾的
query_set = models.User.objects.filter(username__startswith='j')
query_set = models.User.objects.filter(username__endswith='n')
"""
<QuerySet [<User: 当前对象:jason_DSB,年龄:18>]>
<QuerySet [<User: 当前对象:kevin,年龄:40>, <User: 当前对象: Steven,年龄:12>]>
"""
- 查询注册时间
# 查询注册的月份是5月份的数据
query_set = models.User.objects.filter(register_time__month='5')
# 查询注册年份是2020年的数据
query_set = models.User.objects.filter(register_time__year='2020')
一对多外键查询
orm环境:
"""用户表"""
class User(models.Model)
username = models.CharField(max_length=64, verbose_name="用户名")
password = models.CharField(max_length=64, verbose_name="密码")
age = models.IntegerField(verbose_name="年龄")
phone = models.BigIntegerField(verbose_name="手机号码")
email = models.EmailField(verbose_name="个人邮箱")
register_time = models.DateField(auto_now_add=True, verbose_name="注册时间")
def __str__(self):
return f'当前对象:{self.username},年龄:{self.age}'
"""书籍表"""
class Book(models.Model):
name = models.CharField(max_length=64, verbose_name="书名")
price = models.DecimalField(max_digits=8, decimal_places=2, verbose_name="价格")
publish_date = models.DateField(auto_now_add=True, verbose_name="出版日期")
# 一对多关系,外键建在多的那一方
publish = models.ForeignKey(to="Publish")
# 多对多关系,外键推荐建在查询频率较高的那一方
authors = models.ManyToManyField(to="Author")
"""出版社"""
class Publish(models.Model):
name = models.CharField(max_length=64, verbose_name="出版社名称")
addr = models.CharField(max_length=64, verbose_name="出版社地址")
email = models.EmailField(verbose_name="出版社邮箱")
"""作者"""
class Author(models.Model):
name = models.CharField(max_length=32, verbose_name="作者名称")
age = models.IntegerField()
# 一对一关系,外键推荐建在查询频率较高的那一方
author_detail = models.OneToOneField(to='AuthorDetail')
"""作者详情"""
class AuthorDetail(models.Model):
phone = models.BigIntegerField(verbose_name="作者手机")
email = models.EmailField(verbose_name="作者邮箱")
addr = models.CharField(max_length=64, verbose_name="作者联系地址")
一对多外键的增删改查
# 增
方式一:直接写实际字段的id
models.Book.object.create(
name='钢铁是怎样炼成的',
price=70.50,
publish_id=1,
)
方式二:写虚拟字段,对象
publish_obj = models.Publish.object.filter(pk=3).first()
models.Book.object.create(
name='野性的呼唤',
price='100.64',
publish=publish_obj,
)
# 删除(级联删除)
models.Publish.object.filter(pk=3).delete()
# 修改
方式一
models.Book.object.filter(pk=1).update(publish_id=3)
方式二:
publish_obj=models.Publish.object.filter(pk=3).first()
models.Book.object.filter(pk=1).update(publish=publish_obj)
多对多外键的查询(操作第三张表)
# 给图书添加作者
方式一:直接添加作者的主键字段
book_obj = models.Book.objects.filter(pk=4).first()
book_obj.authors.add(1,3) # 为书籍id为4的书籍绑定主键为1,3的作者
方式二:添加作者对象
book_obj = models.Book.objects.filter(pk=6).first()
author_obj1 = models.Author.objects.filter(pk=5).first()
author_obj2 = models.Author.objects.filter(pk=7).first()
book_obj.authors.add(author_obj1,author_obj2)
add给第三张表添加数据,括号内可以是对象,也可以是数字
# 删除图书的作者
book_obj = models.Book.object.filter(pk=8).first()
book_obj.authors.remove(3,5)
方式二:
book_obj = models.Book.object.filter(pk=10).first()
author_obj1 = models.Author.object.filter(pk=1).first()
author_obj2 = models.Author.object.filter(pk=7).first()
book_obj.authors.remove(author_obj1,author_onj2)
# 修改图书的作者
book_obj = models.Book.objects.filter(pk=10).first()
book_obj.authors.set((1,5)) # 括号内必须是一个可迭代对象
方式二:
book_obj = models.Book.objects.filter(pk=8).first()
author_obj1 = models.Author.objects.filter(pk=1).first()
author_obj2 = models.Author.objects.filter(pk=7).first()
book_obj.authors.set((author_obj1,author_obj2))
"""
book_obj.authors.set(1,5)
TypeError: set() takes 2 positional arguments but 3 were given
objs = tuple(objs)
TypeError: 'int' object is not iterable
"""
set:括号内必须是一个可迭代的对象,该对象内,可以是字段,也可以是对象
# 清空
在第三张表关系中,解除图书与作者的绑定关系
book_obj = models.Book.object.filter(pk=1).first()
book_obj.authors.clear() # 括号内不加任何的参数
正反向的概念
"""
正向:外键字段在我表中,我查你就是正向
反向:外键字段不在我这里,我查你就是反向
"""
book >>>外键字段在书那儿(正向)>>> publish
publish >>>外键字段在书那儿(反向)>>> book
结论:
正向查询按字段
反向查询按照表名的小写_set
多表查询
子查询(基于对象的跨表查询)
- 查询书籍主键为4的出版社
# 书籍查出版社(外键在书籍一方,正向查询)
book_obj = models.Book.objects.filter(pk=4).first()
res = book_obj.publish
print(res) # 出版社:东方出版社
- 查询书籍主键为8的作者
# 书籍查作者(外键在书籍一方,正向查询)
book_obj = models.Book.objects.filter(pk=8).first()
res = book_obj.authors.all()
print(res) # <QuerySet [<Author: Author object>, <Author: Author object>]>
- 查询作者“刘.易斯”的邮箱
# 作者查作者详情(外键在书籍一方,正向查询)
author_obj = models.Author.objects.filter(name="刘.易斯").first()
author_obj.author_detail
print(author_obj.author_detail.email)
# 13657440321@126.com
- 查询出版社是东方出版社的书
# 出版社查书籍(外键在书籍一方,反向查询)
publish_obj = models.Publish.objects.filter(name="东方出版社").first()
res = publish_obj.book_set.all()
print(res)
# <QuerySet [<Book: Book object>, <Book: Book object>]>
- 查询作者是"刘.易斯"的书
# 作者查书籍(外键在书籍一方,反向查询)
author_obj = models.Author.objects.filter(name="刘.易斯").first()
res = author_obj.book_set.all()
print(res)
# <QuerySet [<Book: Book object>]>
- 查询住址为“浙江杭州” 的作者
# 由作者详情查作者(外键在作者一方,反向查询)
author_detail_obj = models.AuthorDetail.objects.filter(addr="浙江杭州").first()
res = author_detail_obj.author
print(res) # Author object
总结:
1.正向查询,按字段
2.反向查询,按表名:
(1)查询结果有多个,要加_set.all();
(2)查询结果只有一个,无须加_set.all()
联表查询(基于双下划线的跨表查询)
- 查询“刘.易斯”的年龄和邮箱
# 正向查询
res = models.Author.objects.filter(name="刘.易斯").values('age','author_detail__email')
print(res)
"""
<QuerySet [{'age': 44, 'author_detail__email': '13657440321@126.com'}]>
"""
# 反向查询
res = models.AuthorDetail.objects.filter(author__name="刘.易斯").values('author__age','email')
print(res)
"""
<QuerySet [{'author__age': 44, 'email': '13657440321@126.com'}]>
"""
- 查询书籍主键为4的出版社名称和书籍名称
# 正向查询
res = models.Book.objects.filter(pk=4).values('publish__name','name')
print(res)
"""
<QuerySet [{'publish__name': '东方出版社', 'name': '钢铁是怎样炼成的'}]>
"""
# 反向查询
res = models.Publish.objects.filter(book__pk=4).values('name','book__name')
print(res)
"""
<QuerySet [{'name': '东方出版社', 'book__name': '钢铁是怎样炼成的'}]>
"""
- 查询书籍主键为4的作者姓名
# 正向查询
res = models.Book.objects.filter(pk=4).values('authors__name')
print(res)
"""
<QuerySet [{'authors__name': '奥斯特洛夫斯基'}, {'authors__name': '刘.易斯'}]>
"""
# 反向查询
res = models.Author.objects.filter(book__pk=4).values('name')
print(res)
"""
<QuerySet [{'name': '奥斯特洛夫斯基'}, {'name': '刘.易斯'}]>
"""
- 查询书籍主键是4的作者邮箱
# 正向查询
res = models.Book.objects.filter(pk=4).values('authors__author_detail__email')
print(res)
"""
<QuerySet [{'authors__author_detail__email': '18466075732@163.com'}, {'authors__author_detail__email': '13657440321@126.com'}]>
"""
# 反向查询
res = models.AuthorDetail.objects.filter(author__book__pk=4).values('email')
print(res)
"""
<QuerySet [{'email': '18466075732@163.com'}, {'email': '13657440321@126.com'}]>
"""