单表操作
# django自带的sqlite3数据库对日期格式不是很敏感,处理的时候容易出错 # 将自带的数据库换为mysql,之前有介绍 # 在model.py加入表结构 class User(models.Model): name = models.CharField(max_length=32) age = models.IntegerField() register_time = models.DateField() ''' DateField DateTimeField 两个重要参数 auto_now:每次操作数据的时候,该字段会自动将当前时间更新 auto_now_add:在创建数据的时候会自动将当前创建时间记录下来,之后只要不修改,那么就一直不变 ''' def __str__(self): return '对象输出:%s' % self.name
测试脚本
当你只是想测试django中的某一个py文件内容,那么你可以不用书写前后端交互的形式,而是直接写一个测试脚本即可
脚本代码无论是写在应用下的tests.py还是自己单独开设py文件都可以
''' 测试环境的准备 去manage.py中拷贝前四行代码 然后自己写两行 ''' import os import sys if __name__ == "__main__": os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day64.settings") import django django.setup() # 在这个代码块的下面就可以测试django里面的单个py文件了
单表的增删改查
-
数据的增
# 单表操作 增删改查 # 数据的增加 # 方式一:直接对应标识增加 res = models.User.objects.create(name='xiaozhang',age=35,register_time='2020-01-11') print(res) # 方式二: 将对象方式增加 import datetime now_time = datetime.datetime.now() # 获取当前日期 res_obj = models.User(name='xiaoli',age=25,register_time=now_time) res_obj.save()
-
数据的删除
# 数据的删除 # 方式一 res = models.User.objects.filter(pk=2).delete() # 删除主键值是2的数据 print(res) # (1, {'app01.User': 1}) ''' pk会自动查找到当前表的主键字段,指代的就是当前表的主键字段 用pk之后,就不需要知道当前表的主键字段是什么(例如:uid,pid,sid...) ''' # 方式二 use_obj = models.User.objects.filter(pk=1).first() use_obj.delete()
-
数据的修改
# 数据的修改 res = models.User.objects.filter(pk=3).update(name='xiaohuang') print(res) # 1 # 查找数据的方式还有get方法,该方法返回的直接就是当前数据对象,该方法不推荐使用,因为一旦获取的数据不存在,该方法会直接报错 # 查找数据的方式filter,一般还是用filter方式 user_obj = models.User.objects.filter(pk=2) user_obj1 = models.User.objects.get(pk=2) print(user_obj) # <QuerySet []> 返回是空,但是不不报错 print(user_obj1) # 查找的主键值数据不存在,报错 user_obj.name = 'egonPPP' user_obj.save()
必知必会13条
-
all() 查询所有数据
res = models.User.objects.all() print(res) # <QuerySet [<User: 对象输出:xiaohuang>, <User: 对象输出:xiaozhang>, <User: 对象输出:xiaoli>]>
-
filter() 带有过滤条件的查询
res = models.User.objects.filter(name='xiaoli') print(res) # <QuerySet [<User: 对象输出:xiaoli>]>
-
get() 直接拿数据对象 但是条件不存在直接报错
res = models.User.objects.get(pk=1) print(res) # 报错 app01.models.DoesNotExist: User matching query does not exist.
-
first() 拿queryset里面第一个元素
res = models.User.objects.filter(name='xiaoli').first() print(res) # 对象输出:xiaoli
-
last() 拿queryset里面最后一个元素
res = models.User.objects.filter(name='xiaohuang').last() print(res) # 对象输出:xiaohuang res = models.User.objects.all().last() print(res) # 对象输出:xiaoli
-
values() 可以指定获取的数据字段 select name,age from ... 类似列表套字典
res = models.User.objects.values('name','age') print(res) # <QuerySet [{'name': 'xiaohuang', 'age': 20}, {'name': 'xiaozhang', 'age': 35}, {'name': 'xiaoli', 'age': 25}]>
-
values_list() 也是指定获取数据字段 类似列表套元祖
res = models.User.objects.values_list('name','age') print(res) # <QuerySet [('xiaohuang', 20), ('xiaozhang', 35), ('xiaoli', 25)]>
-
distinct() 去重
res = models.User.objects.values('name','age').distinct() print(res) # <QuerySet [{'name': 'xiaohuang', 'age': 20}, {'name': 'xiaozhang', 'age': 35}, {'name': 'xiaoli', 'age': 25}]> ''' 去重一定要是一模一样的数据才可以,如果带有主键那么肯定是不一样的,必须是不带主键字段才可以 '''
-
order_by() 排序 默认是升序
res = models.User.objects.order_by('age') # 默认升序 print(res) # <QuerySet [<User: 对象输出:xiaohuang>, <User: 对象输出:xiaohuang>, <User: 对象输出:xiaoli>, <User: 对象输出:xiaozhang>]> res = models.User.objects.order_by('-age') # 降序加一个减号 print(res) # <QuerySet [<User: 对象输出:xiaozhang>, <User: 对象输出:xiaoli>, <User: 对象输出:xiaohuang>, <User: 对象输出:xiaohuang>]>
-
reverse() 反转的前提是 数据已经排过序了 order_by()
res = models.User.objects.order_by('age').reverse() print(res) # <QuerySet [<User: 对象输出:xiaozhang>, <User: 对象输出:xiaoli>, <User: 对象输出:xiaohuang>, <User: 对象输出:xiaohuang>]>
-
count() 统计当前数据的个数
res = models.User.objects.count() print(res) # 4
-
exclude() 排除在外
res = models.User.objects.exclude(name='xiaohuang') print(res) # <QuerySet [<User: 对象输出:xiaozhang>, <User: 对象输出:xiaoli>]>
-
exists() 基本用不到因为数据本身就自带布尔值 返回的是布尔值
res = models.User.objects.filter(name='xiaoli').exists() print(res) # True
内部查询封装sql语句(补充)
查询内部封装的sql语句
查询sql语句的方式,只能用于queryset对象,只有queryset对象才能够点击query查看内部的sql语句
# 方式一 query 只有是queryset对象才能够点击query查看内部的sql语句 res = models.User.objects.values_list('name', 'age').query print(res) # SELECT `app01_user`.`name`, `app01_user`.`age` FROM `app01_user` # 方式二 # 所有sql语句都能查询,修改settings配置文件 LOGGING = { 'version': 1, 'disable_existing_loggers': False, 'handlers': { 'console': { 'level': 'DEBUG', 'class': 'logging.StreamHandler', }, }, 'loggers': { 'django.db.backends': { 'handlers': ['console'], 'propagate': True, 'level': 'DEBUG', }, } }
神奇的双下划线查询
# 查询年龄大于20岁的数据 res = models.User.objects.filter(age__gt=20) print(res) # <QuerySet [<User: 对象输出:xiaozhang>, <User: 对象输出:xiaoli>]> # 年龄小于20岁的数据 res = models.User.objects.filter(age__lt=20) print(res) # <QuerySet []> # 大于等于 小于等于 res = models.User.objects.filter(age__gte=20) # 大于等于 print(res) # <QuerySet [<User: 对象输出:xiaohuang>, <User: 对象输出:xiaozhang>, <User: 对象输出:xiaoli>, <User: 对象输出:xiaohuang>]> res1 = models.User.objects.filter(age__lte=20) # 小于等于 print(res1) # <QuerySet [<User: 对象输出:xiaohuang>, <User: 对象输出:xiaohuang>]> # 查询年龄是25或者35 res = models.User.objects.filter(age__in=[25,35]) print(res) # <QuerySet [<User: 对象输出:xiaozhang>, <User: 对象输出:xiaoli>]> # 查询年龄在25到35岁之间的 首尾都要 res = models.User.objects.filter(age__range=[25,35]) print(res) # <QuerySet [<User: 对象输出:xiaozhang>, <User: 对象输出:xiaoli>]> # 查询出名字里面含有h的数据 模糊查询 区分大小写 res = models.User.objects.filter(name__contains='h') print(res) # <QuerySet [<User: 对象输出:xiaohuang>, <User: 对象输出:xiaozhang>, <User: 对象输出:xiaohuang>]> # 查询出名字里面含有l的数据 模糊查询 忽略大小写 res = models.User.objects.filter(name__icontains='l') print(res) # <QuerySet [<User: 对象输出:xiaoli>, <User: 对象输出:xiaoLii>]> # # 查询首字母是x开头的数据 res = models.User.objects.filter(name__startswith='x') print(res) # # 查询最后是以x结尾的数据 res = models.User.objects.filter(name__endswith='x') print(res) # 查询注册时间是2020年1月的数据 res = models.User.objects.filter(register_time__year='2020',register_time__month='01') print(res) # <QuerySet [<User: 对象输出:xiaozhang>, <User: 对象输出:xiaohuang>]> ''' SELECT `app01_user`.`id`, `app01_user`.`name`, `app01_user`.`age`, `app01_user`.`register_time` FROM `app01_user` WHERE (`app01_user`.`register_time` BETWEEN '2020-01-01' AND '2020-12-31' AND EXTRACT(MONTH FROM `app01_user`.`register_time`) = 1) LIMIT 21; args=('2020-01-01', '2020-12-31', 1) '''
多表操作
多表操作我们以图书管理系统为例:
书对出版社:一对多
书对作者:多对多
作者对作者详情:一对一
# 在model.py中建立ORM表结构 # 图书表 class Book(models.Model): title = models.CharField(max_length=64) price = models.DecimalField(max_digits=8,decimal_places=2) publish_date = models.DateField(auto_now_add=True) # 一对多 publish = models.ForeignKey(to='Publish') # 多对的 authors = models.ManyToManyField(to='Authors') # 出版社表 class Publish(models.Model): name = models.CharField(max_length=32) addr = models.CharField(max_length=64) email = models.EmailField() # 该字段类型不是给modles看的,而是给后面校验性组件看的 # 作者表 class Authors(models.Model): name = models.CharField(max_length=32) age = models.IntegerField() # 一对一 author_detail = models.OneToOneField(to='AuthorDetail') # 作者详情表 class AuthorDetail(models.Model): phone = models.BigIntegerField() # 电话号码用BigIntegerField或者CharField addr = models.CharField(max_length=64)
一对多外键增删改查
-
数据的增加
# 增加 给书籍绑定出版社 res = models.Book.objects.create(title='三国演义',price=123.33,publish_id=1) res = models.Book.objects.create(title='论语',price=110.59,publish_id=2) res = models.Book.objects.create(title='红楼梦',price=83.15,publish_id=1) res = models.Book.objects.create(title='聊斋',price=99.35,publish_id=2) # 虚拟字段 对象 给书籍绑定出版社 publish_obj = models.Publish.objects.filter(pk=2).first() print(publish_obj.name) models.Book.objects.create(title='聊斋', price=123.33, publish=publish_obj)
-
数据的删除
# 删除 res = models.Book.objects.filter(pk=5).delete() # 级联删除 print(res) # (3, {'app01.Book_authors': 2, 'app01.Book': 1})
-
数据的修改
# 修改 修改出版社 models.Book.objects.filter(pk=2).update(publish_id=2) # 虚拟字段修改 对象 修改出版社信息 publish_obj = models.Publish.objects.filter(pk=1).first() models.Book.objects.filter(pk=2).update(publish=publish_obj)
多对多外键增删改查
-
数据的增加
# 增加 给书籍添加作者 add # 方式一 book_obj = models.Book.objects.filter(pk=2).first() print(book_obj.title) # 三国演义 print(book_obj.authors) # app01.Authors.None 就类似于已经到了第三张关系表 book_obj.authors.add(1) # 给书籍id为2的书籍绑定一个主键为1的作者 如果已经存在,则不变 book_obj.authors.add(2, 3) # 给书籍id为2的书籍绑定一个主键为2和3的作者 # 方式二 # 1、获取书籍id为2的书籍 book_obj = models.Book.objects.filter(pk=2).first() # 2、获取到作者表中的主键值为1/2/3的数据对象 author_obj = models.Authors.objects.filter(pk=1).first() author_obj1 = models.Authors.objects.filter(pk=2).first() author_obj2 = models.Authors.objects.filter(pk=3).first() print(author_obj) # Authors object print(author_obj.name) # 张三 # 3、给获取到的书籍添加一个作者对象 book_obj.authors.add(author_obj) book_obj.authors.add(author_obj1,author_obj2) ''' 总结:add给第三张表关系添加数据 括号内既可以传数字也可以传对象,并且都支持多个 '''
-
数据的删除
# 删除 remove # 方式一 book_obj = models.Book.objects.filter(pk=2).first() book_obj.authors.remove(2) # 删除书籍主键值是2的,并且作者主键是2的作者 book_obj.authors.remove(1,3) # 删除书籍主键值是2的,并且作者主键是1和3的作者 # 方式二 # 1、获取书籍id为2的书籍 book_obj = models.Book.objects.filter(pk=2).first() # 2、获取到作者表中的主键值为2/3的数据对象 author_obj = models.Authors.objects.filter(pk=2).first() author_obj1 = models.Authors.objects.filter(pk=3).first() # 3、删除获取到的作者 book_obj.authors.remove(author_obj,author_obj1) ''' 总结:remove 括号内既可以传数字也可以传对象,并且都支持多个 '''
-
数据的修改
# 修改 set 修改的值必须是一个可迭代对象 # 方式一 book_obj = models.Book.objects.filter(pk=2).first() book_obj.authors.set([1, 2]) # 括号内必须给一个可迭代对象 book_obj.authors.set([3]) # 括号内必须给一个可迭代对象 # 方式二 # 1、获取书籍id为2的书籍 book_obj = models.Book.objects.filter(pk=2).first() # 2、获取到作者表中的主键值为2/3的数据对象 author_obj = models.Authors.objects.filter(pk=2).first() author_obj1 = models.Authors.objects.filter(pk=3).first() # 3、修改获取到的作者对象 book_obj.authors.set([author_obj, author_obj1]) # 括号内必须给一个可迭代对象 ''' 总结:set 括号内必须传一个可迭代对象,既可以传数字也可以传对象,并且都支持多个 '''
-
数据的清空
# 清空 在第三张关系表中的清空某一个书籍与作者的绑定关系 clear book_obj.authors.clear() ''' 总结:clear 括号内不要加任何参数 '''
正反向的概念
正向:
外键字段在我手上,那么我查你就是正向
反向:
外键字段不在我手上,那么我查你就是反向
# book >>> 外键字段在书哪里(正向) >>> publish # publish >>> 外键字段在书哪里(反向) >>> book ''' 正向查找按字段,反向查找按表名(小写)加_set '''
跨表查询(重点)
子查询(基于对象的跨表查询)
# 查询书籍主键为2的出版社(书查出版社,主键字段在书这边,正向) book_obj = models.Book.objects.filter(pk=2).first() res = book_obj.publish print(res,res.name) # Publish object 东方出版社 # 查询书籍主键为2的作者(书查作者,主键字段在书这边,正向) book_obj = models.Book.objects.filter(pk=2).first() res = book_obj.authors.all() print(res) # <QuerySet [<Authors: Authors object>, <Authors: Authors object>, <Authors: Authors object>]> # 查询作者张三的电话号码(作者查作者详情,主键字段在作者这边,正向) author_obj = models.Authors.objects.filter(name='张三').first() res = author_obj.author_detail print(res) # AuthorDetail object print(res.phone) # 123 ''' 建议: 写ORM语句与SQL语句类似,不要想的一次性写完,可以写一点看一点 正向什么时候需要用到all(): 当结果可能有多个的时候需要加.all() (多对多关系) 当结果为一个的时候,则直接拿到数据对象,无需.all() (一对一,一对多) ''' # 查询出版社是北方出版社出版的书籍(出版社查书,主键字段在书这边,反向) publish_obj = models.Publish.objects.filter(name='北方出版社').first() res = publish_obj.book_set # app01.Book.None res = publish_obj.book_set.all() # <QuerySet [<Book: Book object>]> print(res) # 查询作者是张三写过的书(作者查书,主键字段在书这边,反向) author_obj = models.Authors.objects.filter(name='张三').first() res = author_obj.book_set.all() print(res[1].title) # <QuerySet [<Book: Book object>, <Book: Book object>, <Book: Book object>]> # 查询手机号码是123的作者姓名(作者详情查询作者,主键字段在作者这边,反向) author_detail_obj = models.AuthorDetail.objects.filter(phone='123').first() res = author_detail_obj.authors # Authors object print(res) ''' 反向查询什么时候需要加_set.all(): 当查询结果可能是多个时就必须加_set.all() (一对多,多对多) 当查询结果只有一个时,不需要加_set.all() (一对一) '''
联表查询(基于双下划线的跨表查询)
# 查询张三的手机号和作者姓名 # 正向 res = models.Authors.objects.filter(name='张三').values('name','author_detail__phone') print(res) # <QuerySet [{'name': '张三', 'author_detail__phone': 123}]> # 反向 res = models.AuthorDetail.objects.filter(authors__name='张三').values('authors__name','phone') print(res) # <QuerySet [{'authors__name': '张三', 'phone': 123}]> # 查询书籍主键为2的出版社名称和书的名称 # 正向 res = models.Book.objects.filter(pk=2).values('publish__name','title') print(res) # <QuerySet [{'publish__name': '东方出版社', 'title': '三国演义'}]> # 反向 res = models.Publish.objects.filter(book__pk=2).values('name','book__title') print(res) # <QuerySet [{'name': '东方出版社', 'book__title': '三国演义'}]> # 查询书籍主键为2的作者姓名 # 正向 res = models.Book.objects.filter(pk=2).values('authors__name') print(res) # <QuerySet [{'authors__name': '张三'}, {'authors__name': '李四'}, {'authors__name': '王五'}]> # 反向 res = models.Authors.objects.filter(book__pk=2).values('name') print(res) # <QuerySet [{'name': '张三'}, {'name': '李四'}, {'name': '王五'}]> # 查询书籍主键为2的作者手机号码 # 正向 res = models.Book.objects.filter(pk=2).values('authors__author_detail__phone') print(res) # <QuerySet [{'authors__author_detail__phone': 123}, {'authors__author_detail__phone': 456}, {'authors__author_detail__phone': 789}]> # 反向 res = models.AuthorDetail.objects.filter(authors__book=2).values('phone') print(res) # <QuerySet [{'phone': 123}, {'phone': 456}, {'phone': 789}]>