目录
配置测试脚本文件
单表操作
增加数据
查询数据
修改数据
删除数据
查询十三太保
双下划线查询
连表下的数据增删改
一对多 / 一对一
多对多
跨表查询
基本对象的跨表查询 (子查询)
基于双下划线的跨表查询 (连表查询)
配置测试脚本文件
直接在 App 下面的 test.py 中进行如下配置
注意: 必须完成如下配置之后才能导入我们需要测试的文件
- from django.test import TestCase
- # 1. 从 manage.py copy 这几行代码
- import os
- if __name__ == "__main__":
- os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day55.settings")
- # 2. 自己写两行
- import django
- django.setup()
- # 3. 把上面的环境搭好才能导入我们需要测试的模块
查看内部具体的 SQL 语句可以将下面的代码 copy 到 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',
- },
- }
- }
单表操作
增加数据
增加数据的两种方法
通过 QuerySet 对象的 create 方法创建
通过对象的 save 方法创建
- # 1.QuerySet 对象的 create 方法
- book_obj = models.Books.objects.create(title='三国演义', price=66.66, publish_date='2019-1-1')
- # 2. 对象的 save 方法
- book_obj = models.Books(title='西游记', price=77.77, publish_date='2018-1-1')
- book_obj.save()
查询数据
同样的, 查询数据也有两种方法
通过 QuerySet 对象的 filter 方法查询 ---> 返回的是一个 QuerySet 对象
通过 QuerySet 对象的 get 方法查询 ---> 返回的就是数据对象
注意: 1. 使用 get 方法当条件不存在时会报错
2.ORM 语句的查询都是惰性查询, 当你使用数据的时候才会执行
3. 只要是 QuerySet 对象就可以无限制的使用 QuerySet 的方
? 4. 只要是 QuerySet 对象就可以使用 `.query` 的方法 查看当前结果对应的 sql 语句
- # 1.filter
- res = models.Books.objects.filter(pk=1).first()
- # 查看当前结果对应的 sql 语句
- print(res.query)
- '''
- SELECT `app01_books`.`id`, `app01_books`.`title`, `app01_books`.`price`, `app01_books`.`publish_date` FROM `app01_books` WHERE `app01_books`.`id` = 1
- '''
- # 2.get
- # 查询条件不存在会报错
- res = models.Books.objects.get(pk=4)
- print(res)
- '''
- app01.models.DoesNotExist: Books matching query does not exist.
- '''
修改数据
QuerySet 的 update 的方法
对象. 属性进行修改, 然后 save 方法保存
不推荐使用, 效率低
- # 1.QuerySet 的 update 方法
- models.Books.objects.filter(pk=1).update(price=88.88)
- # 2. 对象的 save()方法
- book_obj = models.Books.objects.filter(pk=1).first()
- book_obj.price = 66.66
- book_obj.save()
删除数据
QuerySet 的 delete 方法
对象的 delete 方法
- # 删除数据的两种方法
- # 1.query set 方法
- models.Books.objects.filter(pk=1).delete()
- # 2. 对象方法
- book_obj = models.Books.objects.filter(pk=2)
- book_obj.delete()
查询十三太保
- +----+----------+-------+--------------+
- | id | title | price | publish_date |
- +----+----------+-------+--------------+
| 1 | 三国演义 | 66.66 | 2019-01-01 |
| 2 | 西游记 | 77.77 | 2018-01-01 |
| 3 | 水浒传 | 88.88 | 2017-01-01 |
| 4 | 红楼梦 | 99.99 | 2016-01-01 |
| 5 | 三国演义 | 66.66 | 2016-01-01 |
- +----+----------+-------+--------------+
- # 1.all 查询所有, 返回 QuerySet 对象
- res = models.Books.objects.all()
- # 2.filter 筛选, 返回 QuerySet 对象
- res = models.Books.objects.filter(pk=1, price=66.66)
- # 3.get 获取的数据对象本身, 条件不存在会报错, 并且条件必须是唯一的, 不然也报错
- res = models.Books.objects.get(title='三国演义')
- # 4.first() 获取 QuerySet 中的第一个数据对象
- res = models.Books.objects.filter().first()
- # 5.last() 获取 QuerySet 中最后一个数据对象
- res = models.Books.objects.all().last()
- # 6.count() 统计数据对象的个数
- num = models.Books.objects.count()
- print(num) # 4
- # 7.values() 获取指定的字段数据, 返回的是一个 queryset 对象, 列表套字典
- res = models.Books.objects.values('title', 'price')
- print(res)
- '''<QuerySet [{'title':'三国演义','price': Decimal('66.66')}, {'title':'西游记','price': Decimal('77.77')}, {'title':'水浒传','price': Decimal('88.88')}, {'title':'红楼梦','price': Decimal('99.99')}]>
- '''
- # 8.values_list() 获取指定的字段数据, 返回的是一个 queryset 对象, 列表套元祖
- res = models.Books.objects.values_list('title', 'price')
- print(res)
- '''<QuerySet [('三国演义', Decimal('66.66')), ('西游记', Decimal('77.77')), ('水浒传', Decimal('88.88')), ('红楼梦', Decimal('99.99'))]>
- '''
- # 9.order_by() 按照字段排序, 返回的是一个 QuerySet 对象
- res1 = models.Books.objects.order_by('price') # 默认是升序
- res2 = models.Books.objects.order_by('-price') # 降序
- # res = models.Books.objects.all().order_by('price')
- # 10.reverse() 颠倒顺序, 和 order_by 联用, 返回的是一个 QuerySet 对象
- res = models.Books.objects.all().order_by('price').reverse()
- # 11.exclude() 排除, 返回的是一个 QuerySet 对象
- res = models.Books.objects.all().exclude(title='三国演义')
- # 12.exist() 判断查询结果是否有值, 返回一个布尔值
- res = models.Books.objects.filter(pk=1).exists()
- print(res)
- # 13.distinct() 去重, 前提是数据必须是完全相同的情况下, 容易忽略主键
- # 主键不同, 因此即使其他字段的值完全一样, 还是会把两个都查询出来
- res1 = models.Books.objects.filter(title='三国演义').distinct()
- res2 = models.Books.objects.values('title').distinct()
- print(res1) # <QuerySet [<Books: Books object>, <Books: Books object>]>
- print(res2) # <QuerySet [{'title': '三国演义'}, {'title': '西游记'}, {'title': '水浒传'}, {'title': '红楼梦'}]>
双下划线查询
- +----+----------------+-------+--------------+
- | id | title | price | publish_date |
- +----+----------------+-------+--------------+
| 1 | 三国演义 | 66.66 | 2019-01-01 |
| 2 | 西游记 | 77.77 | 2018-01-01 |
| 3 | 水浒传 | 88.88 | 2017-01-01 |
| 4 | 红楼梦 | 99.99 | 2016-01-01 |
| 5 | 三国演义 | 66.66 | 2016-01-01 |
| 6 | Three kingdoms | 55.55 | 2015-01-01 |
| 7 | Three Kingdoms | 44.44 | 2014-01-01 | Kingdoms 的 King 是大写
- +----+----------------+-------+--------------+
- # 1.__gt 大于
- res = models.Books.objects.filter(price__gt=80)
- print(res)
- # 2.__lt 小于
- res = models.Books.objects.filter(price__lt=80)
- print(res)
- # 3.__gte 大于等于
- res = models.Books.objects.filter(price__gte=88.88)
- print(res)
- # 4.__lte 小于等于
- res = models.Books.objects.filter(price__lte=77.77)
- print(res)
- # 5.__in 或者
- res = models.Books.objects.filter(price__in=[88.88, 99.99])
- print(res) # 查询结果为空, 是因为我们的价格都是小数, python 小数精度很低
- # 6.__range 范围(顾头顾尾) 相当于 <= x <=
- res = models.Books.objects.filter(price__range=(70, 90))
- print(res)
- # 7.__year
- res = models.Books.objects.filter(publish_date__year='2019')
- print(res)
- # 8.__month 月份
- res = models.Books.objects.filter(publish_date__month='1')
- print(res)
- """
- MySQL 中的模糊查询
- 关键字: like
- 符号:
- % 匹配任意个数字符
- _ 匹配一个字符
- """
- # 9.__startswith 以... 开头
- res = models.Books.objects.filter(title__startswith='三国')
- print(res)
- # 10.__endswith 以... 结尾
- res = models.Books.objects.filter(title__endswith='梦')
- print(res)
- # 11.__contains 包含... (区分大小写)
- res = models.Books.objects.filter(title__contains='king')
- print(res) # <QuerySet [<Books: Books object>]>
- # 12.__icontains 包含...(不区分大小写)
- res = models.Books.objects.filter(title__icontains='king')
- print(res) # <QuerySet [<Books: Books object>, <Books: Books object>]>
连表下的数据增删改
比如我们现在新建的 book 表, 表中的存在 publish_id 外键字段, 我们在表中创建数据时, 该如何给这个字段传值呢?
一对多 / 一对一
- # 一对多
- # 增加数据
- # 1. 实际字段, 传外键的 id 值
- models.Book.objects.create(title='三国演义', price='66.66', publish_date='2019-1-1', publish_id=1)
- # 2. 虚拟字段, 直接传对象
- publish_obj = models.Publish.objects.filter(pk=2).first()
- models.Book.objects.create(title='西游记', price='77.77', publish_date='2018-1-1', publish=publish_obj)
- # 修改数据
- # 1. 实际字段, 传外键 id 值
- models.Book.objects.filter(pk=1).update(publish_id=2)
- # 2. 虚拟字段, 直接传对象
- models.Book.objects.filter(pk=2).update(publish=publish_obj)
- # 删除数据 (默认是级联更新)
- models.Publish.objects.filter(pk=1).delete() # 会删除关联表内相应的行
多对多
多对多关系表的数据操作
- # add 增加多对多关系表数据的两种方法
- """
- add 方法用于向多对多关系表中添加数据
- 支持 对象(包含虚拟外键字段)(1, 2) --> 1, 2 代表的还是关联表的 id 值
- 也支持 对象(包含虚拟外键字段)(author_obj1, author_obj2)
- authors 是建立多对多外键时的虚拟字段, book_obj.authors 可以理解为进入了多对多关系表中
- """
- # 先筛选出一个书籍对象
- book_obj = models.Book.objects.filter(pk=2).first()
- # 1. 添加 id 值
- book_obj.authors.add(2)
- book_obj.authors.add(3, 4) # add 方法也支持多个参数
- # 2. 添加对象
- author_obj1 = models.Book.objects.first(pk=2).first()
- author_obj2 = models.Book.objects.first(pk=3).first()
- book_obj.authors.add(author_obj1, author_obj2)
- # set 方法修改多对多关系表中的数据
- """
- set 方法用于修改多对多关系表中的数据
- 既可传 id 值, 也可以传对象, 注意!!! 必须是可迭代对象!!!
- 支持多个
- """
- book_obj = models.Book.objects.filter(pk=4).first()
- # 1. 添加一个可迭代对象, 里面包含 id 值
- book_obj.authors.set((3, 4))
- # 2. 添加一个可迭代对象, 里面包含对象
- book_obj.authors.set((author_obj1, author_obj2))
- # remove 方法删除多对多关系表数据
- """
- remove 即可以传 id 值, 也可以传对象,
- 并且支持多个, 不需要是可迭代对象
- """
- book_obj = models.Book.objects.filter(pk=2).first()
- # 1. 添加 id 值
- book_obj.authors.remove(3, 4)
- # 2. 添加对象
- book_obj.authors.remove(author_obj1, author_obj2)
- # clear 方法可以清空多对多关系表中某个对象的全部数据
- """
- clear 清空对象的所有数据
- """
- book_obj = models.Book.objects.filter(pk=1).first()
- book_obj.authors.clear()
跨表查询
关系字段在 A 表上, 由 A 表查 B 表是 正向查询, 由 B 表查 A 表是 反向查询
基本对象的跨表查询 (子查询)
正向查询用: 对象. 虚拟字段 --->得到对象 (多个结果要 .all() )
反向查询用类名小写: 对象. 类名 (小写)---> 得到对象 (多个结果需要 _set.all())
- # 1. 查询书籍主键为 2 的出版社名称
- book_obj = models.Book.objects.filter(pk=2).first()
- print(book_obj.publish) # 虚拟字段, 拿到的出版社对象
- print(book_obj.publish.name)
- # 2. 查询书籍主键的为 3 的作者姓名
- book_obj = models.Book.objects.filter(pk=4).first()
- print(book_obj.authors.all()) # 多个作者对象
- """
- 当我们反向查询的结果可能有多个时, 需要加_set.all()
- """
- # 3. 查询出版社的是东方出版社出版的书
- publish_obj = models.Publish.objects.filter(name='东方出版社').first()
- print(publish_obj.book_set.all())
- # 5. 查询作者是 alpha 写过的书籍
- author_obj = models.Author.objects.filter(name='alpha').first()
- print(author_obj.book_set.all())
- # 6. 查询手机号是 111 的作者姓名
- author_detail_obj = models.AuthorDetail.objects.filter(phone='111').first()
- print(author_detail_obj.author.name)
基于双下划线的跨表查询 (连表查询)
- # 1. 查询书籍 pk 为 2 的出版社名称
- # 正向
- res = models.Book.objects.filter(pk=2).values('publish__name')
- print(res)
- # 反向
- models.Publish.objects.filter(book__pk=2).values('name')
- print(res)
- # 2. 查询书籍 pk 为 2 的作者姓名和邮箱
- # 正向
- res = models.Book.objects.filter(pk=2).values('authors__name', 'authors__email')
- print(res)
- # 反向
- res = models.Author.objects.filter(book__pk=2).values('name', 'email')
- print(res)
- # 3. 查询作者是 bravo 的家庭地址
- # 正向
- res = models.Author.objects.filter(name='bravo').values('author_detail__addr')
- print(res)
- # 反向
- res = models.AuthorDetail.objects.filter(author__name='bravo').values('addr')
- print(res)
- # 查询书籍为 pk 是 2 的作者的手机号
- # 正向
- res = models.Book.objects.filter(pk=2).values('authors__author_detail__phone')
- print(res)
- # 反向
- res = models.Author.objects.filter(book__pk=2).values('author_detail__phone')
- print(res)
来源: http://www.bubuko.com/infodetail-3306692.html