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)
book表
class Publish(models.Model):
    name = models.CharField(max_length=32)
    addr = models.CharField(max_length=64)
publish表
class Author(models.Model):
    name = models.CharField(max_length=32)
    age = models.IntegerField()

    # 作者详情   一对一    外键字段建在任意一方均可 推荐你建在查询频率较高的表
    author_detail = models.OneToOneField(to='AuthorDetail')
author表
class AuthorDetail(models.Model):
    phone = models.BigIntegerField()
    addr = models.CharField(max_length=32)
authorDetail表

一对多

:两种方式

  - 直接写实际的表字段

  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)
posted @ 2020-01-08 19:36  treeter  阅读(494)  评论(0编辑  收藏  举报