day55-Django配置测试脚本、ORM查询、跨表正反向查询

配置测试脚本

当你想单独测试django中某一个py文件,需要手动配置测试脚本

#在manage.py中拷贝前四行代码,可以直接写在应用名下的test.py中
import os

if __name__ == '__main__':
    os.environ.setdefault('DJANGO_SETTINGS_MODULE','day55.seetings')
    
    import django
    django.setup()
    from app01 import models

ORM普通查询

创建数据

create

#字段值可以是对象 
obj = models.Table.objects.create(key=value,)

对象绑定方法

obj = models.Table(key=value,)
obj.save()

修改数据

Queryset方法

#py会自动查找到当前表的主键字段
models.Table.objects.filter(pk=1).update(key=value,)
  • filter查询出来的结果都是一个Queryset对象

  • 只要是queryset对象就可以无限制的调用queryset方法

  • 只要是queryset对象就可以.query查看当前结果内部对应的sql语句

    res = models.Table.objects.filter(pk=1)
    print(res.query)
    

    对象方法

    #不推荐使用,利用对象的修改,实质是重写记录的所有字段,效率低
    
    book_obj = models.Books.objects.get(pk=1)
    book_obj.price = 222.66
    book_obj.save()
    

    get和filter的区别

    • filter获取到的是一个Queryset对象,类似于一个列表
    • get获取到的是数据对象本身
    • 当条件不存在的情况下,filter返回空,get直接报错

删除数据

queryset方法

models.Table.objects.filter(pk=1).delete()

对象方法

obj = models.Table.objects.get(pk=1)
obj.delete()

查找数据

orm语句的查询默认都是惰性查询,只有真正要使用数据的时候才会执行orm语句

夺命13条

  1. # all()	查询所有	返回Queryset对象
    res = models.Table.objects.all()
    
  2. # filter()	筛选	相当于sql中的where关键字
    res = models.Table.objects.filter(pk=1,)
    
  3. # get()	筛选		获取到的是对象本身	条件不存在直接报错
    res = models.Table.objects.get(title='西游记',)
    
  4. # first()	取queryset中的第一个数据对象
    res = models.Books.objects.filter(title='西游记').first()
    
  5. # last()		取queryset中的最后一个数据对象
    res = models.Books.objects.filter(title='西游记').last()
    
  6. # count()  统计数据的个数   数字
    num = models.Books.objects.count()
    print(type(num))
    
  7. # values()  获取数据对象中指定的字段的值    返回queryset对象  列表套字典
    res = models.Books.objects.values('title','price')
    print(res)
    # <QuerySet [{'title': '三国演义', 'price': Decimal('222.66')}, {'title': '红楼梦', 'price': Decimal('888.99')}, {'title': '西游记', 'price': Decimal('444.66')}, {'title': '西游记', 'price': Decimal('666.22')}]>
    
  8. # values_list()  获取数据对象中指定的字段的值   返回queryset对象  列表套元祖
    res = models.Books.objects.values_list('title','price')
    print(res)
    #<QuerySet [('三国演义', Decimal('222.66')), ('红楼梦', Decimal('888.99')), ('西游记', Decimal('444.66')), ('西游记', Decimal('666.22'))]>
    
  9. # order_by()      按照指定的字段排序
    res = models.Books.objects.order_by('price')  # 默认是升序
    res1 = models.Books.objects.all().order_by('price')  # 默认是升序   两者等价 下面的方式 语义更明确
    # 降序  字段前面加负号
    res1 = models.Books.objects.all().order_by('-price')
    print(res1)
    
  10. # reverse()      颠倒顺序   前提是跌倒的对象必须有顺序(提前排序之后才能跌倒)
    res = models.Books.objects.all()
    res1 = models.Books.objects.all().reverse()
    res2 = models.Books.objects.all().order_by('price')
    res3 = models.Books.objects.all().order_by('price').reverse()
    print(res2,res3)
    
  11. # exclude()      排除什么什么之外   queryset对象
    res = models.Books.objects.all().exclude(title='三国演义')
    print(res)
    <QuerySet [<Books: 红楼梦>, <Books: 西游记1>, <Books: 西游记2>]>
    
  12. # exists()      判断查询结果是否有值 返回结果是一个布尔值	鸡肋
    res = models.Books.objects.filter(pk=1).exists()
    print(res)
    
  13. # distinct()    对查询结果进行去重操作     去重的前提:数据必须是完全想要的情况下 才能# 够去重(容易忽略主键),多和values()连用
    res = models.Books.objects.values('title','price')
    res = models.Books.objects.values('title','price').distinct()
    print(res)
    
#values和values_list
# 查询价格小于400 的书籍
res = models.Book.objects.filter(price__lt=400).values_list()
res1 = models.Book.objects.filter(price__lt=400).values()
print(res)
print(res1)
'''
<QuerySet [(4, '西游记', Decimal('333.00'), datetime.date(2019, 10, 29), 3)]>
<QuerySet [{'id': 4, 'title': '西游记', 'price': Decimal('333.00'), 'publish_date': datetime.date(2019, 10, 29), 'publish_id': 3}]>
'''
# values_list是列表套元组,只返回值;
# values是列表套字典,返回字段名和值的键值对

双下划线查询

# modls.py

from django.db import models

# Create your models here.
class Books(models.Model):
    title = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=8,decimal_places=2)
    publish_date = models.DateField()


    def __str__(self):
        return self.title


# 表查询 以图书管理系统为例
class Book(models.Model):
    title = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=8,decimal_places=2)
    publish_date = models.DateField(auto_now_add=True)
    """
    auto_now:每次修改的数据的时候 都会自动更新修改书籍(展示最新的一次修改时间)
    auto_now_add:当数据创建出来的时候 会自动将创建时间记录下来
    """
    publish = models.ForeignKey(to='Publish')
    authors = models.ManyToManyField(to='Author')

class Publish(models.Model):
    name = models.CharField(max_length=32)
    addr = models.CharField(max_length=64)

    def __str__(self):
        return self.name


class Author(models.Model):
    name = models.CharField(max_length=32)
    email = models.EmailField()  # 对应到数据库中仅仅是varchar(254) 没有任何的限制条件 该字段只要是字符串就可以
    # 仅仅是为了表达语义   如何限制  后期需要借助于校验性组件
    author_detail = models.OneToOneField(to='AuthorDetail')

    def __str__(self):
        return self.name


class AuthorDetail(models.Model):
    phone = models.BigIntegerField()
    addr = models.CharField(max_length=64)

    def __str__(self):
        return self.addr


# test.py 查询脚本
# 查询价格大于500的书籍
# res = models.Books.objects.filter(price__gt=500).value_list()
# print(res)
# 查询价格小于400 的书籍
# res = models.Books.objects.filter(price__lt=400)
# print(res)
# 查询价格大于等于500
# res = models.Books.objects.filter(price__gte=444.66)  对数字精确度不敏感
# res = models.Books.objects.filter(price__gte=500)
# print(res)
# 查询价格小于等于500的书籍
# res = models.Books.objects.filter(price__lte=500)
# print(res)

# 查询价格是222.66或者444.22或者500的书籍
# res = models.Books.objects.filter(price__in=[222,444,500])
# print(res)

# 查询价格在200到800之间的书籍
# res = models.Books.objects.filter(price__range=(200,800))  # 顾头顾尾
# print(res)

# 查询出版日期是2019年的书籍
# res = models.Books.objects.filter(publish_date__year='2019')
# print(res)
# 查询出版日期是1月份的书籍
# res = models.Books.objects.filter(publish_date__month='1')
# print(res)

# 模糊查询
"""
MySQL中的模糊查询
    关键字 like
        模糊匹配的符号
            %:匹配任何个数的任意字符
            _:匹配一位任意的字符
"""
# 查询书籍是以三开头的书
# res = models.Books.objects.filter(title__startswith='三')
# print(res)
# 查询书籍是以义结尾的书
# res = models.Books.objects.filter(title__endswith='1')
# print(res)
# 查询书籍名称中包含游字的书籍
# res = models.Books.objects.filter(title__contains='游')
# print(res)

# 查询书籍名称中包含字母p的书籍
# res = models.Books.objects.filter(title__contains='p')  # 默认区分大小写
# res = models.Books.objects.filter(title__icontains='p')  # 忽略大小写 加i
# print(res)

# 一对多字段数据的增删改查
# 增
# 第一种
# models.Book.objects.create(title='三国演义',price=222.33,publish_id=1)  # 直接传表里面的实际字段 跟数据主键值  publish_id
# 第二种
# publish_obj = models.Publish.objects.filter(pk=2).first()
# models.Book.objects.create(title='红楼梦',price=444.33,publish=publish_obj)  # 传虚拟字段  跟数据对象即可

# 查

# 改
# 第一种
# models.Book.objects.filter(pk=1).update(publish_id=2)
# 第二种
# publish_obj = models.Publish.objects.filter(pk=1).first()
# models.Book.objects.filter(pk=1).update(publish=publish_obj)

# 删
# models.Publish.objects.filter(pk=1).delete()  # 默认就是级联删除 级联更新

# 多对多字段数据的增删改查
# 增
# book_obj = models.Book.objects.filter(pk=2).first()
# print(book_obj.publish)  # 点外键字段 可能会直接获取到外键关联的数据对象
# 给当前这一本书绑定作者
# 麻瓜做法  自己直接去操作第三张表
# print(book_obj.authors)  # 已经跨到第三张表了
# book_obj.authors.add(1)  # 在第三张表里面给书籍绑定一个主键为1的作者
# book_obj.authors.add(1,2)  # 在第三张表里面给书籍绑定一个主键为1的作者
# author_obj = models.Author.objects.filter(pk=1).first()
# author_obj1 = models.Author.objects.filter(pk=2).first()
# # book_obj.authors.add(author_obj)
# book_obj.authors.add(author_obj,author_obj1)
"""
add方法 能够朝第三张关系表添加数据
    即支持传数字
        add(1,2)
    也支持传对象
        add(author_obj,author_obj1)
    并且两者都可以是多个
"""

# 改
# book_obj = models.Book.objects.filter(pk=2).first()
# # book_obj.authors.set((1,3))
# # book_obj.authors.set([1,])
# author_obj = models.Author.objects.filter(pk=1).first()
# author_obj1 = models.Author.objects.filter(pk=2).first()
# book_obj.authors.set((author_obj,author_obj1))
"""
set修改多对多关系表中的数据
    既可以传数字也可以传对象
    但是需要注意的是括号内必须是可迭代对象
    都支持多个
        set((1,3))
        set((author_obj,author_obj1))
"""

# 删
# book_obj = models.Book.objects.filter(pk=2).first()
# book_obj.authors.remove(100)
# book_obj.authors.remove(1,2)
# author_obj = models.Author.objects.filter(pk=1).first()
# author_obj1 = models.Author.objects.filter(pk=2).first()
# # book_obj.authors.remove(author_obj)
# book_obj.authors.remove(author_obj,author_obj1)
"""
remove既可以传数字 也可以穿对象
    并且都支持传多个 不需要迭代
        remove(1,2)
        remove(author_obj,author_obj1)
"""
# 清空  删除某个数据在第三张表中的所有记录
# book_obj = models.Book.objects.filter(pk=2).first()
# book_obj.authors.clear()
"""
clear清空书籍相关所有记录  括号内不需要传递参数 
"""
# 跨表查询(******)
"""
正反向查询
        关系字段在谁哪 由谁查谁就是正向
        如果关系字段 就是反向
    正向查询按字段
    反向查询按表名小写 + _set
"""
# 基于对象的跨表查询         子查询  分步操作
# 1.查询书籍主键为2的出版社名称
# book_obj = models.Book.objects.filter(pk=2).first()
# print(book_obj.publish)  # 出版社对象
# print(book_obj.publish.name)
# 2.查询书籍主键为4的作者姓名
# book_obj = models.Book.objects.filter(pk=4).first()
# print(book_obj.authors)  # app01.Author.None
# print(book_obj.authors.all())
# 3.查询作者是jason的手机号码
# author_obj = models.Author.objects.filter(name='jason').first()
# print(author_obj.author_detail)
# print(author_obj.author_detail.phone)
"""
什么时候需要加all 
当正向查询点击外键字段数据有多个的情况下 需要.all()
app01.Author.None  一旦看到该结果 只需要加.all()即可


在写orm语句的时候跟你写sql语句一样 不要想着一次性写完
写一点查一点再写一点
"""
# 4.查询出版社是东方出版社出版过的书籍
# publish_obj = models.Publish.objects.filter(name='东方出版社').first()
# # print(publish_obj.book_set)  # app01.Book.None
# print(publish_obj.book_set.all())

# 5.查询作者是jason写过的书籍
# author_obj = models.Author.objects.filter(name='jason').first()
# # print(author_obj.book_set)  # app01.Book.None
# print(author_obj.book_set.all())  # app01.Book.None

# 6.查询手机号是120的作者姓名
# author_detail_obj = models.AuthorDetail.objects.filter(phone=120).first()
# print(author_detail_obj.author)
# print(author_detail_obj.author.email)
"""
什么时候反向查询的时候表名小写需要加_set
    一对多
    多对多

一对一不需要加_set
"""

# 基于双下滑线的跨表查询     联表操作
"""
inner join
left join
right join
union
"""
# 1.查询书籍pk为2的出版社名称
# 正向
# res = models.Book.objects.filter(pk=2).values('publish__name')  # 写外键字段就相当于已经跨到外键字段所关联的表
# 你想要改表的哪个字段信息 你只需要加__获取即可
# print(res)
# 反向
# 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)
"""
models后面点的谁 就以谁为基表
"""

# 3.查询作者是egon的家庭地址
# res = models.Author.objects.filter(name='egon').values('author_detail__addr')
# print(res)
# res = models.AuthorDetail.objects.filter(author__name='egon').values('addr')
# print(res)


# 4.查询出版社是东方出版社出版过的书的名字
# res = models.Publish.objects.filter(name='东方出版社').values('book__title')
# print(res)
# res = models.Book.objects.filter(publish__name='东方出版社').values('title')
# 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)

  • 大于/小于

    filed__gt = xxx
    filed__lt = xxx
    
  • 大于等于/小于等于

    #对数字精确度不敏感
    filed__gte = xxx
    filed__lte = xxx
    
  • field__in=[x,y,z]
    
  • 之间

    filed__range(x,y)  # 包含x,y
    
  • 模糊查询

    • 以。。。开头

      field__startswith='xxx'
      
    • 以。。。结尾

      field__endswith = 'xxx'
      
    • 包含。。。

      field__contains = 'xxx'  # 默认区分大小写
      field__icontains = 'xxx'  # 忽略大小写
      
  • 一对多字段数据的操作

    • 增/改:可以直接出传实际字段的值,虚拟字段传对象

    • 删:

      models.Publish.objects.filter(pk=1).delete()  # 默认就是级联删除 级联更新
      
  • 多对多字数数据的操作

    • 增:

      book_obj = models.Book.objects.filter(pk=2).first()
      print(book_obj.publish)  # 点外键字段 可能会直接获取到外键关联的数据对象
      
      book_obj.authors.add(1,)  # 在第三张表里面给书籍绑定一个主键为1的作者,可多个
      
      author_obj = models.Author.objects.filter(pk=1).first()
      book_obj.authors.add(author_obj)  # add也支持传对象
      
    • 改:

      
      book_obj = models.Book.objects.filter(pk=2).first()
      #set会删除authors中所有book_obj的记录,并重新添加
      book_obj.authors.set((1,3))
      #支持传对象
      # author_obj = models.Author.objects.filter(pk=1).first()
      # author_obj1 = models.Author.objects.filter(pk=2).first()
      # book_obj.authors.set((author_obj,author_obj1))
      
    • 删:

      book_obj = models.Book.objects.filter(pk=2).first()
      book_obj.authors.remove(1,)
      
      author_obj = models.Author.objects.filter(pk=1).first()
      book_obj.authors.remove(author_obj)
      
      
    • 清空:

      # 清空  删除某个数据在第三张表中的所有记录
      book_obj = models.Book.objects.filter(pk=2).first()
      book_obj.authors.clear()
      

跨表查询

正向查询:包含关系字段的表,查关联表;按字段查询

反向查询,不含关系字段的表,查关联表;按表名小写_set

正向查询

子查询

# 1.查询书籍主键为2的出版社名称,通过.外键字段可以获取对象
book_obj = models.Book.objects.filter(pk=2).first()
print(book_obj.publish)  # 出版社对象
print(book_obj.publish.name)
# 2.查询书籍主键为4的作者姓名
book_obj = models.Book.objects.filter(pk=4).first()
print(book_obj.authors)  # app01.Author.None
print(book_obj.authors.all())  # 当查询结果有多个值时,使用all()

反向查询

在一对多和多对多的情况下,使用**_ set ;一对一情况下不需要加_ set **

基于双下划线的跨表查询

两表

# 1.查询书籍pk为2的出版社名称
# 正向
res = models.Book.objects.filter(pk=2).values('publish__name')  # 写外键字段就相当于已经跨到外键字段所关联的表
# 你想要改表的哪个字段信息 你只需要加__获取即可
print(res)
# 反向
res1 = models.Publish.objects.filter(book__pk=2).values('name')
print(res1)

多表

# 查询书籍pk是2的作者的手机号
res = models.Book.objects.filter(pk=2).values('authors__author_detail__phone')
print(res)

#可以有不同的基准
res1 = models.Author.objects.filter(book__pk=2).values('author_detail__phone')
print(res1)

posted on 2019-11-27 21:09  shenblogs  阅读(107)  评论(0)    收藏  举报

导航