django model层

Django模型层ORM学习笔记

首先测试文件需要做一些准备工作,我使用的是test.py,需要在manage.py文件夹中拷贝以下内容

from django.test import TestCase

# Create your tests here.
import os


if __name__ == "__main__":
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day58.settings")
    import django
    django.setup()
    # 以上语句固定写法,接下来写导入models模块的语句
    from app01 import models
    # 从这开始正常写ORM操作数据库的语句即可

查看ORM操作数据库内部走的mysql语句

	当我们操作数据库拿回来的是QuerySet对象是,我们可以通过QuerySet对象.query查看内部的mysql语句,那么返回的不是QuerySet对象时该怎么做呢?只需要在settings.py中找个地方将下面语句放着即可(运用日志)。

ORM单表查询,双下划线查询

为了更好的了解ORM对数据库的操作,我们选择连接mysql数据库,毕竟sqlite3还是有点小瑕疵的。

ORM有很多常用字段,其中字段DateField的参数有auto_now跟auto_now_add,如果我们配置了这两个参数中的一个,创建数据对象时DateField字段会自动创建,无需我们传值。配置auto_now_add=True,创建数据记录的时候会把当前时间添加到数据库,之后就不在变化。配置上auto_now=True,每次更新数据记录的时候会更新该字段。友情提示,DateFIeld和DateTImeField可以直接接收datetime对象。

ForeignKey有to_field参数,可以指定你想跟一张表的什么字段建立外键,不写默认是id
models.py中创建表:

from django.db import models

# Create your models here.
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')


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


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.CharField(max_length=32)
    addr = models.CharField(max_length=32)

单表查询:

1新增数据

# 第一种:有返回值,并且就是当前被创建的数据对象
modles.Publish.objects.create(name='',addr='',email='')

# 第二种:先实例化产生对象,然后调用save方法保存
book_obj = models.Publish(name='',addr='',email='')
book_obj.save()

在这里插入图片描述
2修改数据

# 基于数据对象
user_obj = models.User.objects.filter(name='jason').first()
user_obj.age = 17
user_obj.save()

# 基于queryset对象
models.User.objects.filter(name='kevin').update(age=66)

删除数据


# 基于数据对象
# user_obj = models.User.objects.filter(name='owen').first()
# user_obj.delete()

# 基于queryset对象
 models.User.objects.filter(name='egon').delete()

查询数据
之前常用的查询是all查所有及filter条件查询,其中filter条件查询有多个条件时,各条件是and的关系。filter查询传多个参数时,各参数间是and的关系:

models.User.objects.filter(name='egon', age=18) # name='egon' and 'age'=18

其实查询数据能用到的方法一共有13个(均是QuerySet对象的方法),最好都记住。然后QuerySet对象能够无限制的点QuerySet方法:
  在过滤得到的QuerySet对象的基础上再进行过滤,依次类推
models.User.objects.filter(过滤条件1).filter(过滤条件2).order_by(排序依据的字段名).reverse()

# reverse方法使用的前提是QuerySet对象被排序过,order_by是排序(排序依据的字段名前加-号即是反向排序)
<1> all():                 #查询所有结果
<2> filter(**kwargs):      #它包含了与所给筛选条件相匹配的对象
<3> get(**kwargs):         #返回与所给筛选条件相匹配的对象,返回结果有且只有一个,如果符合筛选条件的对象超过一个或者没有都会抛出错误。
<4> exclude(**kwargs):     #它包含了与所给筛选条件不匹配的对象
<5> order_by(*field):      #对查询结果排序('-id')/('price')
                    
<6> reverse():             #对查询结果反向排序     >>>前面要先有排序才能反向
<7> count():               #返回数据库中匹配查询(QuerySet)的对象数量。
<8> first():               #返回第一条记录
<9> last():                #返回最后一条记录
<10> exists():             #如果QuerySet包含数据,就返回True,否则返回False
<11> values(*field):       #返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的并不是一系列model的实例化对象,而是一个可迭代的字典序列
<12> values_list(*field):  #它与values()非常相似,它返回的是一个元组序列,values返回的是一个字典序列
<13> distinct():           #从返回结果中剔除重复纪录

着重记住values方法(普通QuerySet对象:<QuerySet [<Author: Author object>]>):
在这里插入图片描述
在上述13种QuerySet方法中,有些方法执行完返回的不一定是QuerySet对象,可能是其他对象。

# 返回QuerySet对象的方法
all()、filter()、exclude()、order_by()、reverse()、distinct()

# 特殊的QuerySet
values()        #返回一个可迭代的字典序列
values_list()  #返回一个可迭代的元祖序列

# 返回具体数据对象的
get()、first()、last()

# 返回布尔值的方法
exists() #判断QuerySet对象是否为空,空返回False,否则返回True

# 返回数字的方法
count()  #返回当前QuerySet对象中的数据对象个数

双下划线查询
上述的查询中,filter的查询条件都是name=‘值’,age=值之类的,可是我们查询时条件肯定会有age>18,age<=18等情况。这个时候就需要用的双下划线查询。
大于 小于 大于等于 小于等于

filter(price__gt='90')   # 大于 great than
filter(price__lt='90')    # 小于 less than
filter(price__gte='90') # 大于等于 great than equal
filter(price__lte='90')  # 小于等与 less than equal

存在于某几个条件中

filter(age__in=['11','22','33'])

在某个范围内

filter(age__range=[50,90])

模糊查询

filter(title__contains='p')   # 区分大小写
filter(title__icontains='P')  # 不区分大小写

以什么开头,以什么结尾

# 查询名字以j开头的用户
res = models.User.objects.filter(name__startswith='j')
print(res)

# **查询名字以n结尾的用户**
res = models.User.objects.filter(name__endswith='n')
print(res)

按年查询(针对DateField和针对DateTImeField)

filter(create_time__year='2017')

多表操作

一对多记录增删改查
新增(主键用pk传比较好,比较稳)

 # 直接写id
models.Book.objects.create(title='红楼梦',price=66.66,publish_id=1)

# 传数据对象
publish_obj = models.Publish.objects.filter(pk=2).first()
models.Book.objects.create(title='三国演义',price=199.99,publish=publish_obj)

修改

# Queryset修改
models.Book.objects.filter(pk=1).update(publish_id=3)
publish_obj = models.Publish.objects.filter(pk=2).first()
models.Book.objects.filter(pk=1).update(publish=publish_obj)

# 对象修改
book_obj = models.Book.objects.filter(pk=1).first()
book_obj.publish_id = 3  # 点表中真实存在的字段名
book_obj.save()

publish_obj = models.Publish.objects.filter(pk=2).first()
book_obj.publish = publish_obj  # 点orm中字段名 传该字段对应的表的数据对象
book_obj.save()

删除

# 使用QuerySet对象删除
models.Book.objects.filter(pk=1).delete()
models.Publish.objects.filter(pk=1).delete()

# 使用数据对象删除
book_obj = models.Book.objects.filter(pk=3).first()
book_obj.delete()

多对多记录增删改查

添加(add)

# 拿到id=3的书籍数据对象
book_obj = models.Book.objects.filter(pk=3).first()

# 数据对象.authors可以直接跳到多对多那张表里
# add传值传作者id,可以传多个
book_obj.authors.add(1)
book_obj.authors.add(2,3)

# add传值支持传对象,而且可以传多个
author_obj = models.Author.objects.filter(pk=1).first()
author_obj1 = models.Author.objects.filter(pk=3).first()
book_obj.authors.add(author_obj)
book_obj.authors.add(author_obj,author_obj1)

修改(set)

# 拿到id=3的书籍数据对象
book_obj = models.Book.objects.filter(pk=3).first()

# 数据对象.authors可以直接跳到多对多那张表里
# set传值传作者id,可以传多个
book_obj.authors.set((1,))
book_obj.authors.set((1,2,3))

# set传值支持传对象,而且可以传多个
author_list = models.Author.objects.all()
book_obj = models.Book.objects.filter(pk=3).first()
book_obj.authors.set(author_list)

删除(remove)

# 拿到id=3的书籍数据对象
book_obj = models.Book.objects.filter(pk=3).first()

# 数据对象.authors可以直接跳到多对多那张表里
# remove传值支持传值,而且可以传多个
book_obj.authors.remove(1)
book_obj.authors.remove(2,3)

# remove传值支持传对象,而且可以传多个
author_obj = models.Author.objects.all().first()
author_list = models.Author.objects.all()
book_obj.authors.remove(author_obj)
book_obj.authors.remove(*author_list)  #需要将Queryset对象打散

清空(clear)

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

**

正向反向查询

**

# 一对一
# 正向:author---关联字段在author表里--->authordetail        按字段
# 反向:authordetail---关联字段在author表里--->author        按表名小写
    # 查询jason作者的手机号   正向查询
    # 查询地址是 :山东 的作者名字   反向查询
  
# 一对多
# 正向:book---关联字段在book表里--->publish        按字段
# 反向:publish---关联字段在book表里--->book        按表名小写_set.all() 因为一个出版社对应着多个图书

# 多对多
# 正向:book---关联字段在book表里--->author        按字段
# 反向:author---关联字段在book表里--->book        按表名小写_set.all() 因为一个作者对应着多个图书
  
  

# 连续跨表
    # 查询图书是三国演义的作者的手机号,先查书,再正向查到作者,在正向查手机号

# 总结:基于对象的查询都是子查询,这里可以用django配置文件自动打印sql语句的配置做演示

基于对象的表查询
正向

# 查询书籍是三国演义的出版社邮箱
book_obj = models.Book.objects.filter(title='三国演义').first()
print(book_obj.publish.email)

# 查询书籍是水浒传的作者的姓名
book_obj = models.Book.objects.filter(title='水浒传').first()
print(book_obj.authors)  # app01.Author.None
print(book_obj.authors.all())

# 查询作者为jason电话号码
user_obj = models.Author.objects.filter(name='jason').first()
print(user_obj.authordetail.phone)

反向

# 查询出版社是东方出版社出版的书籍   一对多字段的反向查询
publish_obj = models.Publish.objects.filter(name='东方出版社').first()
print(publish_obj.book_set)  # app01.Book.None
print(publish_obj.book_set.all())

# 查询作者jason写过的所有的书           多对多字段的反向查询
author_obj = models.Author.objects.filter(name='jason').first()
print(author_obj.book_set)  # app01.Book.None
print(author_obj.book_set.all())

# 查询作者电话号码是110的作者姓名     一对一字段的反向查询
authordetail_obj = models.AuthorDetail.objects.filter(phone=110).first()
print(authordetail_obj.author.name)

基于双下划线的查询
正向示例

# 查询书籍为三国演义的出版社地址
res = models.Book.objects.filter(title='三国演义').values('publish__addr','title')
print(res)

# 查询书籍为水浒传的作者的姓名
res = models.Book.objects.filter(title='水浒传').values("authors__name",'title')
print(res)

# 查询作者为jason的家乡
res = models.Author.objects.filter(name='jason').values('authordetail__addr')
print(res)


反向示例

# 查询南方出版社出版的书名
res = models.Publish.objects.filter(name='南方出版社').values('book__title')
print(res)

# 查询电话号码为120的作者姓名
res = models.AuthorDetail.objects.filter(phone=120).values('author__name')
print(res)

# 查询作者为jason的写的书的名字
res = models.Author.objects.filter(name='jason').values('book__title')
print(res)

# 查询书籍为三国演义的作者的电话号码
res = models.Book.objects.filter(title='三国演义').values('authors__authordetail__phone')
print(res)

反向示例

练习:

# 查询jason作者的手机号
# 正向
res = models.Author.objects.filter(name='jason').values('authordetail__phone')
print(res)
# 反向
res = models.AuthorDetail.objects.filter(author__name='jason').values('phone')
print(res)

# 查询出版社为东方出版社的所有图书的名字和价格
# 正向
res = models.Publish.objects.filter(name='东方出版社').values('book__title','book__price')
# print(res)
反向
# res = models.Book.objects.filter(publish__name='东方出版社').values('title','price')
print(res)

# 查询东方出版社出版的价格大于400的书
# 正向
res = models.Publish.objects.filter(name="东方出版社",book__price__gt=400).values('book__title','book__price')
print(res)
# 反向
res = models.Book.objects.filter(price__gt=400,publish__name='东方出版社').values('title','price')
print(res)

在查询的时候先把orm查询语句写出来,再看用到的条件是否在当前表内,在就直接获取,不在就按照正向按字段反向按表名小写来查即可。切忌一口吃成胖子。
聚合查询(aggregate)
需要先导入模块:

from django.db.models import Max,Min,Count,Sum,Avg

示例

# 查询所有书籍的作者个数
res = models.Book.objects.filter(pk=3).aggregate(count_num=Count('authors'))
print(res)

# 查询所有出版社出版的书的平均价格
res = models.Publish.objects.aggregate(avg_price=Avg('book__price'))
print(res)  # 4498.636

# 统计东方出版社出版的书籍的个数
res = models.Publish.objects.filter(name='东方出版社').aggregate(count_num=Count('book__id'))
print(res)

分组查询(annotate)

# 统计每个出版社出版的书的平均价格
res = models.Publish.objects.annotate(avg_price=Avg('book__price')).values('name','avg_price')
print(res)

# 统计每一本书的作者个数
res = models.Book.objects.annotate(count_num=Count('authors')).values('title','count_num')
print(res)

# 统计出每个出版社卖的最便宜的书的价格
res = models.Publish.objects.annotate(min_price=Min('book__price')).values('name','min_price')
print(res)

# 查询每个作者出的书的总价格
res = models.Author.objects.annotate(sum_price=Sum('book__price')).values('name','sum_price')
print(res)

分组查询例子
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值