Django(数据查询)
如何治单独测试django中的某一个py文件
书写测试脚本:
- 在应用下的tests.py或者自己建一个py文件
- 在文件中书写以下内容:
if __name__ == "__main__": os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day53.settings") import django django.setup()
创建表格:
class Movie(models.Model): title = models.CharField(max_length=64) price = models.DecimalField(max_digits=8,decimal_places=2) publish_time = models.DateField() # 年月日
create():创建数据,返回值就是当前被创建数据的对象本身
models.Movie.objects.create(title='齐天大圣',price=999.23,publish_time='2016-1-1')
all():查询所有数据,返回的是queryset对象
res = models.Movie.objects.all()
fileter():按照一定条件查询,条件可以是多个,条件直接关系是and,返回的是queryset对象
res = models.Movie.objects.filter(pk=1,title='python入门')
get():直接获取对象本身,但是不推荐使用,因为当查询条件不存在时候,会报错
res = models.Movie.objects.get(pk=1)
values():获取指定字段的值,返回的是一个列表套字典的queryset对象
res = models.Movie.objects.values('title','publish_time')
values_list():获取指定字段的值,返回的是一个列表套元组的queryset对象
res = models.Movie.objects.values_list('title','price')
first():取第一个元素对象
res = models.Movie.objects.filter().first()
last():取最后一个元素对象
res = models.Movie.objects.last()
update():更新数据,返回的是受影响的行数
res = models.Movie.objects.filter(pk=1).update(title='齐天大圣2',price=666)
delete():删除数据,返回的是受影响的表和行数
res = models.Movie.objects.filter(pk=3).delete()
count():统计数据条数
res = models.Movie.objects.count()
order_by():按照指定字段排序,默认是升序,前面加减号就是降序
res = models.Movie.objects.order_by('price') # 升序
res = models.Movie.objects.order_by('-price') # 降序
exclude():排除什么之外,少选条件
res = models.Movie.objects.exclude(pk=1)
exists():判断前面的对象是否有数据,返回的是布尔值
res = models.Movie.objects.filter(pk=1000).exists()
reverse():反转
res = models.Movie.objects.order_by('price').reverse()
distinct():去重
res = models.Movie.objects.values('title','price').distinct()
双下划线查询
__gt:大于
res = models.Movie.objects.filter(price__gt=200)
__lt:小于
res = models.Movie.objects.filter(price__lt=500)
__gte:大于等于
res = models.Movie.objects.filter(price__gte=200)
__lte:小于等于
res = models.Movie.objects.filter(price__lte=500)
__in:在XX中
res = models.Movie.objects.filter(price__in=[123,666,876])
__range:在一个区间内,顾头也顾尾
res = models.Movie.objects.filter(price__range=(200,900))
__contains:模糊查询,默认是区分大小写,前面加i不区分
res = models.Movie.objects.filter(title__contains='p') # 区分‘p’的大小写
res = models.Movie.objects.filter(title__icontains='p') # 不区分‘p’的大小写
__year/month/day...:查询指定的年或者月或天等其他的时间
res = models.Movie.objects.filter(publish_time__year=2014)
res = models.Movie.objects.filter(publish_time__month=1)
外键字段的增删改查
class Book(models.Model): title = models.CharField(max_length=32) price = models.DecimalField(max_digits=8,decimal_places=2) publish_time = models.DateField(auto_now_add=True) # 该字段新增数据自动添加 无需考虑 # 出版社 一对多 外键字段建在多的一方 publish = models.ForeignKey(to='Publish') # 作者 多对多 外键字段建在任意一方均可 推荐你建在查询频率较高的表 authors = models.ManyToManyField(to='Author') # 库存数 kucun = models.BigIntegerField(default=1000) # 卖出数 maichu = models.BigIntegerField(default=1000)
class Publish(models.Model): name = models.CharField(max_length=32) addr = models.CharField(max_length=64)
class Author(models.Model): name = models.CharField(max_length=32) age = models.IntegerField() # 作者详情 一对一 外键字段建在任意一方均可 推荐你建在查询频率较高的表 author_detail = models.OneToOneField(to='AuthorDetail')
class AuthorDetail(models.Model): phone = models.BigIntegerField() addr = models.CharField(max_length=32)
一对多
增:两种方式
- 直接写实际的表字段
models.Book.objects.create(title='大闹天宫',price=123.23,publish_id=2)
- 添加对象
publish_obj = models.Publish.objects.get(pk=1)
models.Book.objects.create(title='哪吒闹海',price=66.66,publish=publish_obj)
改:两种方式
- 直接写实际的表字段
models.Book.objects.filter(pk=1).update(publish_id=3)
- 添加对象
publish_obj = models.Publish.objects.get(pk=4)
models.Book.objects.filter(pk=1).update(publish=publish_obj)
多对多
给书籍绑定作者关系:add
add专门给第三张关系表添加数据,括号内即可以传数字也可以传对象,并且都支持传多个
book_obj = models.Book.objects.filter(pk=1).first() # 书籍和作者的关系是由第三张表绝对 也就意味着你需要操作第三张表 book_obj.authors.add(1) # 给书籍绑定一个主键为1的作者 book_obj.authors.add(2,3) # 也可以一次绑定多个作者
移除书籍与作者的绑定关系:remove
remove专门给第三张关系表移除数据,括号内即可以传数字也可以传对象,并且都支持传多个
book_obj = models.Book.objects.filter(pk=1).first() book_obj.authors.remove(2) book_obj.authors.remove(1,3)
修改书籍与作者的关系 :set
set修改书籍与作者的关系 ,括号内支持传数字和对象,但是需要是可迭代对象
book_obj = models.Book.objects.filter(pk=1).first() book_obj.authors.set((3,)) book_obj.authors.set((2,3)) author_obj = models.Author.objects.get(pk=2) author_obj1 = models.Author.objects.get(pk=3) book_obj.authors.set([author_obj,author_obj1])
清空书籍与作者关系:clear
clear清空关系,不需要任何的参数
book_obj = models.Book.objects.filter(pk=1).first()
book_obj.authors.clear()
跨表查询
正反向:
正向:跨表查询的时候,外键字段是否在当前数据对象中,如果在,查询另外一张关系表方式叫正向查询
反向: 如果不在,就是反向查询
口诀:
正向查询按外键字段
反向查询按表名小写
基于对象的跨表查询(子查询)
1.查询书籍pk为1的出版社名称
book_obj = models.Book.objects.filter(pk=1).first()
res = book_obj.publish.name
2.查询书籍pk为2的所有作者的姓名
book_obj = models.Book.objects.filter(pk=2).first() # print(book_obj.authors) # 返回的是:app01.Author.None author_list = book_obj.authors.all() for author_obj in author_list: print(author_obj.name)
3.查询作者pk为1的电话号码
author_obj = models.Author.objects.filter(pk=1).first()
res = author_obj.author_detail.phone
小结:正向查询的时候,当外键字段对应的数据可以有多个的时候需要加.all(),若没有多个,则点外键字典即可获取到对应的数据对象
4.查询出版社名称为东方出版社出版过的书籍
publish_obj = models.Publish.objects.filter(name='东方出版社').first() # print(publish_obj.book_set) # app01.Book.None res = publish_obj.book_set.all()
5.查询作者为jason写过的书
author_obj = models.Author.objects.filter(name='jason').first() res = author_obj.book_set.all()
6.查询手机号为120的作者姓名
author_detail_obj = models.AuthorDetail.objects.filter(phone=120).first()
res = author_detail_obj.author.name
小结:基于对象的反向查询,表名小写是否需要加_set.all()
基于双下划线跨表查询(链表查询)
1.查询书籍pk为1的出版社名称
正向:
res = models.Book.objects.filter(pk=1).values('publish__name') # 写外键字段,就意味着你已经在外键字段管理的那张表中
反向:
# res = models.Publish.objects.filter(book__pk=1) # 出版社pk为1的书籍对应的出版社 res = models.Publish.objects.filter(book__pk=1).values('name')
2.查询书籍pk为1的作者姓名和年龄
正向:
res = models.Book.objects.filter(pk=1).values('title','authors__name','authors__age')
反向:
res = models.Author.objects.filter(book__pk=1).values('name','age')
3.查询作者是jason的年龄和手机号
正向:
res = models.Author.objects.filter(name='jason').values('age','author_detail__phone')
反向:
res = models.AuthorDetail.objects.filter(author__name='jason').values('phone','author__age')
4.查询书籍pk为的1的作者的手机号
正向:
res = models.Book.objects.filter(pk=1).values('authors__author_detail__phone')
反向:
res = models.AuthorDetail.objects.filter(author__book__pk=1).values('phone')
小结:只要表之间有关系,你就可以通过正向的外键字段或者反向的表名小写连续跨表操作
聚合查询
from django.db.models import Max,Min,Avg,Count,Sum
# 查询所有书的平均价格 res = models.Book.objects.aggregate(avg_num=Avg('price')) print(res) # 查询价格最贵的书 res = models.Book.objects.aggregate(max_num=Max('price')) print(res) # 全部使用一遍 res = models.Book.objects.aggregate(Avg("price"), Max("price"), Min("price"),Count("pk"),Sum('price')) print(res)
分组查询
# 1.统计每一本书的作者个数 res = models.Book.objects.annotate(author_num=Count('authors')).values('title','author_num') print(res) # 2.统计出每个出版社卖的最便宜的书的价格 res = models.Publish.objects.annotate(min_price=Min('book__price')).values('name','min_price','book__title') print(res) # 3.统计不止一个作者的图书 res = models.Book.objects.annotate(author_num=Count('authors')).filter(author_num__gt=1).values('title') print(res) # 4.查询各个作者出的书的总价格 res = models.Author.objects.annotate(price_sum=Sum('book__price')).values('name','price_sum') print(res)
F与Q查询
from django.db.models import F,Q
1.查询库存数大于卖出数的书籍
res = models.Book.objects.filter(kucun__gt=F('maichu'))
2.将所有书的价格提高100
res = models.Book.objects.update(price=F('price') + 100)
3.查询书的名字是python入门或者价格是1000的书籍
res = models.Book.objects.filter(Q(title='python入门'),Q(price=1000)) # 逗号是and关系 res = models.Book.objects.filter(Q(title='python入门')|Q(price=1000)) # |是or关系 res = models.Book.objects.filter(~Q(title='python入门')|Q(price=1000)) # ~是not关系
小结:F能获取到表中某个字段对应的值;Q能够改变查询的条件关系 and or not
Q的高阶用法
q = Q() q.connector = 'or' # q对象默认也是and关系 可以通过connector改变or q.children.append(('title','python入门')) q.children.append(('price',1000)) res = models.Book.objects.filter(q) print(res)