Django模型层1

Django模型层

一、如何配置测试脚本

  1. 直接在某一个应用下的tests文件中书写下面的内容:

    # 搭建测试脚本,先去 manage.py 中copy下面的三行代码到test文件中
    import os
    
    if __name__ == "__main__":
        os.environ.setdefault("DJANGO_SETTINGS_MODULE", "Books_Management_System.settings")
    	# 下面自己写两行
        import django
        django.setup()
        # 至此测试脚本搭建完毕
        # 下面可以开始写测试代码
        from app01 import models
        res = models.Book.objects.all()
    
    # 如果不写,会报错
    
    
  2. 直接新建一个任意名称的py文件,在里面写上面的配置。

二、单表操作

1. 创建数据

  1. create方法

    book_obj = models.Book.objects.create(title='大主宰',price=35.5,publisher_id=1)
    
  2. 利用对象的绑定方法save()

    book_obj = models.Book(title='最初进化',price=666.6,publisher_id=1)
    book_obj.save()
    

2. 修改数据

  1. update方法

    先通过filter筛选出需要修改的对象。

    filter选出的对象类型为queryset对象,可以无限制的调用queryset方法。

    而且queryset对象可以通过‘对象.query’的方式查看操作内部对应的SQL语句。

    models.Book.objects.filter(pk=8).update(publisher_id=3)
    
  2. 利用get获取到的对象的方法

    book_obj =models.Book.objects.get(pk=9)
    print(book_obj)
    book_obj.publisher_id = 3
    book_obj.save()
    

get和filter区别:

  1. filter获取到的是一个queryset对象,类似于一个列表

  2. get获取到的直接就是数据对象本身。

当条件不存在的情况下:

filter不报错直接返回一个空。推荐使用filter方法。

get直接报错。所以不推荐使用get方法。

3. 删除数据

  1. 利用queryset的delete方法

    models.Book.objects.filter(pk=10).delete()
    
  2. 利用get获取到的对象的delete方法

    book_obj = models.Book.objects.get(pk=9)
    book_obj.delete()
    

4. 查询数据(必知必会13条)

4.1 配置 终端打印所有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',
        },
    }
}

4.2 必知必会13条

只可以直接用于queryset对象的方法。

  1. all()

    查询所有

    返回queryset对象

    res = models.Book.objects.all()
    print(res)
    
  2. filter()

    筛选,相当于原生sql语句的where关键字

    返回queryset对象

    res = models.Book.objects.filter(pk=2,title='王牌进化')
    print(res)
    
  3. get()

    获取数据对象本身,只能获取一个对象,并且查询条件必须是唯一的

    res = models.Book.objects.get(title='最终进化')
    res1 = models.Book.objects.filter(title='最初进化')
    print(res,res1)
    
    # 最终进化  <QuerySet [<Book: 最初进化>]>
    
  4. first()

    取第一个数据对象

    res = models.Book.objects.filter(title='最初进化').first()
    print(res)
    
  5. last()

    取最后一个数据对象

    res = models.Book.objects.filter(title='最初进化').last()
    print(res)
    
  6. count()

    统计数据的个数,返回的是整形

    num = models.Book.objects.count()
    print(num,type(num))
    
  7. values()

    获取数据对象中指定的字段的值,返回queryset列表套字典

    res = models.Book.objects.values('title', 'price')
    print(res)
    
  8. values_list()

    获取数据对象中指定的字段的值,可以有多个,返回列表套元组,元祖中只有值。

    res = models.Book.objects.values_list('title', 'price')
    print(res)
    
  9. order_by()

    所有数据按照指定字段排序,默认是升序。

    如果字段名前面加负号就可以降序排列。

    # 默认是升序
    res = models.Book.objects.order_by('price')  
    # 默认是升序,上下两者等价。下面的方式语义更明确
    res1 = models.Book.objects.all().order_by('price')  
    # 要降序,字段前面加负号
    res2 = models.Book.objects.all().order_by('-price')
    print(res,res1,res2)
    
  10. reverse()

    颠倒顺序,前提是颠倒的对象必须有顺序。

    也就是说必须提前排序之后才能颠倒。

    res = models.Book.objects.all()
    print(res)
    res1 = models.Book.objects.all().reverse()
    print(res1)
    res2 = models.Book.objects.all().order_by('price')
    print(res2)
    res3 = models.Book.objects.all().order_by('price').reverse()
    print(res3)
    
  11. exclude()

    排除某一条记录,取反。

    res = models.Book.objects.all().exclude(title='最初进化')
    print(res)
    
  12. exists()

    判断查询结果是否有值,返回结果是一个布尔值

    res = models.Book.objects.filter(pk=11).exists()
    print(res)
    
  13. distinct()

    对查询结果进行去重,前提是数据必须完全相同,才能去重。id也会算在内。

    res = models.Book.objects.values('title', 'price')
    res1 = models.Book.objects.values('title','price').distinct()
    print(res)
    print(res1)
    

三、神奇的双下划线查询

  1. __gt:大于

    # 查询价格大于50的书籍
    res = models.Book.objects.filter(price__gt=50)
    print(res)
    
  2. __lt:小于

    # 查询价格小于40 的书籍
    res = models.Book.objects.filter(price__lt=40)
    print(res)
    
  3. __gte:大于等于

    # 查询价格大于等于50
    # 对数字精确度不敏感
    res = models.Book.objects.filter(price__gte=222.2)  
    res2 = models.Book.objects.filter(price__gte=50)
    print(res)
    print(res2)
    
  4. __lte:小于等于

    # 查询价格小于等于50的书籍
    res = models.Book.objects.filter(price__lte=50)
    print(res)
    
  5. __in=列表:或者,在列表中选择

    # 查询价格是222.2或者66或者50的书籍
    res = models.Book.objects.filter(price__in=[222.2,66,50])
    print(res)
    
  6. __range=元组:在元组的两个数之间,而且顾头顾尾

    # 查询价格在200到800之间的书籍
    res = models.Book.objects.filter(price__range=(200,800))  # 顾头顾尾
    print(res)
    
  7. __year:筛选年份

    # 查询出版年份是2019年的书籍
    res = models.Book.objects.filter(publish_date__year='2019')
    print(res)
    
  8. __month:筛选月份

    # 查询出版日期是11月份的书籍
    res = models.Book.objects.filter(publish_date__month='11')
    print(res)
    
  9. __day:筛选日期

    # 查询出版日是1的书籍
    res = models.Book.objects.filter(publish_date__day='27')
    print(res)
    
  10. __startswith:以。。。开头

    # 查询书籍是以王开头的书
    res = models.Book.objects.filter(title__startswith='王')
    print(res)
    
  11. __endswith:以。。。结尾

    # 查询书籍是以化结尾的书
    res = models.Book.objects.filter(title__endswith='化')
    print(res)
    
  12. __contains:包含某个字符,区分大小写

    # 查询书籍名称中包含主字的书籍
    res = models.Book.objects.filter(title__contains='主')
    print(res)
    
  13. __icontains:不包含某个字符,不区分大小写(ignore)

    # 查询书籍名称中不包含字母进的书籍
    res2 = models.Book.objects.filter(title__icontains='进')
    print(res2)
    

四、表设计特殊字段

1. DateField

年-月-日 格式的时间

  1. auto_now=True:每次修改数据的时候,都会自动更新修改数据(展示最新的一次修改数据)
  2. auto_now_add=True:当数据创建时,会自动将创建时间记录下来

2. DateTimeField

年-月-日-时-分-秒 格式的时间

五、外键字段(一对多)的增删改查

1. 增

  1. 实际真实字段,传数值

    models.Book.objects.create(title='三国演义', price=222.33, publish_id=1)
    
  2. 类中你写的字段,直接放对象

    publish_obj = models.Publisher.objects.filter(pk=2).first()
    models.Book.objects.create(title='红楼梦',price=444.33,publish=publish_obj)
    
    

2. 改

  1. 直接改实际字段

    models.Book.objects.filter(pk=1).update(publish_id=2)
    
  2. 直接传对象

    publish_obj = models.Publisher.objects.filter(pk=1).first()
    models.Book.objects.filter(pk=1).update(publish=publish_obj)
    

3. 删

特点:

级联删除,出版社删除,出版社对应的图书也被删除

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

六、外键字段(多对多)的增删改查

book_obj = models.Book.objects.filter(pk=2).first()
# 点外键字段 可能会直接获取到外键关联的数据对象
print(book_obj.publisher)

麻瓜式做法:自己直接去操作第三张表

1. 增

add():

通过obj.多对多外键字段.add()增加第三张表的数据,既支持传数字,也支持传对象,并且都可以传多个。

print(book_obj.authors)  # 已经跨到第三张表了
# 直接传值
book_obj.authors.add(4)  # 在第三张表里面给书籍绑定一个主键为4的作者 
book_obj.authors.add(1,2)  # 在第三张表里添加多个作者

# 传对象
author_obj = models.Author.objects.filter(pk=12).first()
book_obj.authors.add(author_obj)

2. 改

set():

通过obj.多对多外键字段.set()修改第三张表的数据,修改多对多关系表中的数据。

这里的改指的是重置,也就是先删再增。set括号内的参数为重置字段值后的数据。

同样支持传数字和对象,而且set括号内必须传可迭代对象:元组或列表。就算只有一个值,也必须要是一个列表或元组。(1,)这样的才可以。传对象也是一样。

且都支持多个。

book_obj = models.Book.objects.filter(pk=2).first()
book_obj.authors.set((1,2))
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))

3. 删

级联删除。

  1. remove():既可以传参数,也可以传对象。也支持传多个参数,且传多个参数是时不需要传容器类参数。

    # 删数值
    book_obj = models.Book.objects.filter(pk=2).first()
    book_obj.authors.remove(1)
    book_obj.authors.remove(2,3)
    # book_obj.authors.remove(100)  # 也不会报错
    
    # 删对象
    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)
    
  2. clear():清空。

    删除某个对象在第三张表中的所有记录,括号内不需要传递参数。

    book_obj = models.Book.objects.filter(pk=2).first()
    book_obj.authors.clear()
    

七、跨表查询

1. 正反向查询

关系字段(foreignkey)在谁那儿,由谁开始查就是正向。

如果关系字段不在谁那儿,由谁开始查就是反向。

1.1 正向查询

正向查询按字段.

1.2 反向查询

一对一按表名小写。

一对多或多对多按表名小写+_set

2. 子查询

基于对象的跨表层查询,分布操作。

# A表与B表为多对多的关系,外键在表A上

​```正向查询```
# 先筛选出对象,在通过对象查询
a_obj = models.A.objects.filter()
# 通过 a_obj.b外键.b表中的要查询的字段 查询b中字段
print(a_obj.b.name)

​```反向查询```
# 先筛选出对象,在通过对象查询
b_obj = models.B.objects.filter()
# 在通过“字段名+__set”反向查询出想要的字段值
print(b_obj.A.name__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.all())  # queryset对象
for author in book_obj.authors.all():
    print(author.name))

# 3.查询作者是唐家三少的手机号码
author_obj = models.Author.objects.filter(name='唐家三少').first()
print(author_obj.Author_detail,type(author_obj.Author_detail))
print(author_obj.Author_detail.phone_number)

# 4.查询出版社是进化出版社出版过的书籍
publisher_obj = models.Publisher.objects.filter(name='进化出版社').first()
book_queryset = publisher_obj.book_set.all()
print(book_queryset)
for book in book_queryset:
    print(book.title)

# 5.查询作者是卷土的沙滩写过的书籍
author_obj = models.Author.objects.filter(name='卷土的沙滩').first()
book_queryset = author_obj.book_set.all()
print(book_queryset)
for book in book_queryset:
    print(book.title)

# 6.查询手机号是12580的作者姓名
authdetail_obj = models.AuthorDetail.objects.filter(phone_number='12580').first()
# 一对一反向查询不需要加 “_set”
print(authdetail_obj.author.name)

什么时候需要加all:

当正向查询点击外键字段数据有多个的情况下,需要.all()

一旦看到app01.Author.None 只需要加.all()即可。

在写orm语句的时候跟你写sql语句一样,不要想着一次性写完写一点查一点再写一点。

3. 连表查询

基于双下划线的跨表查询 (mysql中的join)。一条语句就能查询。

models后面点的谁,就以谁为基表。

通过基表queryset对象.values()的方法查询数据。

values()里面字段放什么,查出来的字典的键就是什么。

​```正向查询```
# 在values()内写外键字段就相当于已经跨到外键字段所关联的表上,这时候在字段后面加上 ```__+关联表的字段```,就可以获取该外键外键关联表上的字段值。

​```反向查询```
# 在filter()内写上 ‘表名小写+__条件’ 用来筛选对象,再在后面直接 '.values()' 获取值。
# values()括号内放字段名。
# 如果是需要跨多表,那就在values()的括号中不停地加'__+字段名',每加一个'__'就会跨一下表,最终跨到你需要差的那张表上。

实例:

# 1.查询书籍pk为2的出版社名称
# 正
res = models.Book.objects.filter(pk=2).values('publisher__name').first()
print(res)
# 反
res = models.Publisher.objects.filter(book__pk=2).values('name').first()
print(res)

# 2.查询书籍pk为2的作者姓名和邮箱
# 正
res1 = models.Book.objects.filter(pk=2).values('authors__name','authors__email')
print(res1)
# 反
res = models.Author.objects.filter(book__pk=2).values('name','email').first()
print(res)

# 3.查询作者是天蚕土豆的家庭地址
# 正
res = models.Author.objects.filter(name='天蚕土豆').values('Author_detail__addr').first()
print(res)
# 反
res = models.AuthorDetail.objects.filter(author__name='天蚕土豆').values('addr').first()
print(res)


# 4.查询出版社是天蚕出版社出版过的书的名字
# 正
res = models.Publisher.objects.filter(name='天蚕出版社').values('book__title')
for book in res:
    print(book)
# 反
res = models.Book.objects.filter(publisher__name='天蚕出版社').values('title')
    for book in res:
print(book)


# 跨多表
# 5.查询书籍pk是2的作者的手机号
# 正
res = models.Book.objects.filter(pk=2).values('authors__Author_detail__phone_number').first()
print(res)
# 反
res = models.Author.objects.filter(book__pk=2).values('Author_detail__phone_number').first()
print(res)
# 反2
res = models.AuthorDetail.objects.filter(author__book__pk=2).values('phone_number').first()
print(res)
posted @ 2019-11-27 21:58  Donner  阅读(165)  评论(0编辑  收藏  举报