Django框架-模型层

一、单表查询之必知必会13条

1、时间字段中的两个关键性参数

create_time = models.DateField()  # 年月日
create_time = models.DateTimeField() # 年月日时分秒
# 两个关键性参数
# auto_now:每次操作数据 都会自动刷新当前操作的时间
# auto_now_add:在创建数据的时候 会自动将创建时间记录下来 后续的修改不会影响该字段

2、搭建测试环境

在django中,你可以写一个单独测试某一个py文件的测试脚本,不需要再频繁的走web请求

搭建步骤:

  • 新建一个py文件,或者直接使用app下面的test.py文件
  • 从manage.py中复制三行代码到test.py内
import os

if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day54.settings")
# 上面是从manage.py中复制过来的
import django
django.setup()
# 再写这两行代码,测试环境就搭建好了

3、单表的增删改查

  • 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)
create_time = models.DateField() # 年月日
# create_time = models.DateTimeField() # 年月日 时分秒 def __str__(self):
return self.title
# 方式1: create
book_obj = models.Book.objects.create(title='三国',price=19.99,create_time='2019-11-11') # 方式2:对象点save()方法
from datetime import datetime
ctime = datetime.now()
book_obj = models.Book(title='xxx',price=96.66,create_time=ctime)
book_obj.save()
print(models.Book.objects.all())
print(models.Book.objects.get(id=1))
print(models.Book.objects.get(pk=1))
"""
pk会自动查找到当前数据的主键字段
"""
print(models.Book.objects.filter(pk=2))
# get方法拿到的是Book对象,而all和filter拿到的是queryset对象
# 1.update方法
models.Book.objects.filter(pk=1).update(title='三国演义')
# 2.对象.save()
book_obj = models.Book.objects.get(pk=1)
book_obj.price = 666.66
book_obj.save()
# delete方法
models.Book.objects.filter(pk=2).delete()

4、必知必会13条

# < 1 > all(): 查询所有结果
# < 2 > filter(**kwargs): 它包含了与所给筛选条件相匹配的对象
# < 3 > get(**kwargs): 返回与所给筛选条件相匹配的对象,返回结果有且只有一个,如果符合筛选条件的对象超过一个或者没有都会抛出错误。(源码就去搂一眼~诠释为何只能是一个对象)
# < 4 > exclude(**kwargs): 它包含了与所给筛选条件不匹配的对象
print(models.Book.objects.exclude(pk=1)) # 只要pk不是1的数据全部查询出来 # < 5 > order_by(*field): 对查询结果排序('-id') / ('price')
print(models.Book.objects.order_by('price')) # 默认是升序
print(models.Book.objects.order_by('-price')) # 加负号就是降序 # < 6 > reverse(): 对查询结果反向排序 >> > 前面要先有排序才能反向
print(models.Book.objects.order_by('price').reverse()) # < 7 > count(): 返回数据库中匹配查询(QuerySet)的对象数量。
print(models.Book.objects.count()) # 对查询出来的结果进行一个计数 # < 8 > first(): 返回第一条记录
print(models.Book.objects.filter(pk=1).first()) # < 9 > last(): 返回最后一条记录
print(models.Book.objects.all())
print(models.Book.objects.all().last()) # < 10 > exists(): 如果QuerySet包含数据,就返回True,否则返回False
print(models.Book.objects.filter(pk=1000))
print(models.Book.objects.filter(pk=1000).exists()) # < 11 > values(*field): 返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的并不是一系列model的实例化对象,而是一个可迭代的字典序列
print(models.Book.objects.values('title','price')) # 得到的结果是列表套字典 # < 12 > values_list(*field): 它与values()非常相似,它返回的是一个元组序列,values返回的是一个字典序列
print(models.Book.objects.values_list('title','price')) # 得到的结果是列表套元组 # < 13 > distinct(): 从返回结果中剔除重复纪录
"""
去重的前提是 一定要有完全重复的数据 才能去重
"""
print(models.Book.objects.filter(title='三国演义').distinct()) # 无效的去重
print(models.Book.objects.values('title','price','create_time').distinct()) # 13个必会操作总结
# 返回QuerySet对象的方法有
all()
filter()
exclude()
order_by()
reverse()
distinct() # 特殊的QuerySet
values() # 返回一个可迭代的字典序列
values_list() # 返回一个可迭代的元祖序列 # 返回具体对象的
get()
first()
last() # 返回布尔值的方法有
exists() # 返回数字的方法有
count()

二、Django终端打印SQL语句

问题:查看orm内部sql语句的方法有哪些?

1、如果是queryset对象,那么可以点query直接查看该queryset的内部sql语句

2、在django项目的配置文件中,配置一下参数即可实现所有的orm在查询的时候自动打印对应的sql语句

# 配置代码
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'console':{
'level':'DEBUG',
'class':'logging.StreamHandler',
},
},
'loggers': {
'django.db.backends': {
'handlers': ['console'],
'propagate': True,
'level':'DEBUG',
},
}
}

三、神奇的双下划线查询

# 查询价格大于200的书籍
res = models.Book.objects.filter(price__gt=200)
print(res)
# 查询价格小于200的书籍
res = models.Book.objects.filter(price__lt=200)
print(res) # 查询价格大于等于200.22的书籍
res = models.Book.objects.filter(price__gte=200.22)
print(res)
# 查询价格小于等于200.22的书籍
res = models.Book.objects.filter(price__lte=200.22)
print(res) # 查询价格要么是200,要么是300,要么是666.66
res = models.Book.objects.filter(price__in=[200,300,666.66])
print(res)
# 查询价格在200到800之间的
res = models.Book.objects.filter(price__range=(200,800)) # 两边都包含
print(res) # 查询书籍名字中包含p的
"""原生sql语句 模糊匹配
like
% 多个字符
_ 单个字符
"""
res = models.Book.objects.filter(title__contains='p') # 仅仅只能拿小写p
res = models.Book.objects.filter(title__icontains='p') # 忽略大小写
print(res) # 查询书籍是以三开头的
res = models.Book.objects.filter(title__startswith='三')
res1 = models.Book.objects.filter(title__endswith='p')
print(res)
print(res1) # 查询出版日期是2017的年(******)
res = models.Book.objects.filter(create_time__year='2017')
print(res)
# 还可以查月和日(month day)

四、图书管理系统表创建

1、表关系:

  • 一对多ForeignKey

  • 一对一OneToOneField,可以用ForeignKey代替:ForeignKey(unique=True)

    上面两个关键字创建出来的字段会自动加上_id后缀

  • 多对多ManyToManyField

    该字段并不会真正在表中展示出来,他仅仅是一个虚拟字段,他有两个功能,一是告诉orm自动创建第三张表,二是帮助orm跨表查询

2、建表

  • 新建数据库

  • Django默认的数据库改为MySQL

    修改配置文件

    __init__文件中导入pymysql模块

  • models文件中创建模型表

from django.db import models

# Create your models here.
class Book(models.Model):
title = models.CharField(max_length=255)
price = models.DecimalField(max_digits=8,decimal_places=2)
publish_date = models.DateField(auto_now_add=True)
# 库存数
kucun = models.IntegerField(null=True)
# 卖出数
maichu = models.IntegerField(null=True)
publish = models.ForeignKey(to='Publish') # 默认是跟publish的主键字段做的一对多外键关联
authors = models.ManyToManyField(to='Author')
# 虚拟字段 1.自动创建第三张表 2.帮助orm跨表查询
def __str__(self):
return self.title class Publish(models.Model):
name = models.CharField(max_length=32)
addr = models.CharField(max_length=32)
# email = models.EmailField() # 就是varchar(254)
def __str__(self):
return self.name class Author(models.Model):
name = models.CharField(max_length=32)
age = models.IntegerField()
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)
"""
models.py中的模型类__str__方法 必须返回一个字符串形式数据!!!
"""
def __str__(self):
return self.addr

注意点:

  • CharField必须指定最大长度
  • DecimalField可以指定最大长度以及小数部分的长度
  • DateField设置auto_now_add=True时只会记录记录创建时的时间,之后就不会改变
  • EmailField在数据库中就是varchar类型
  • publish = models.ForeignKey(to='Publish') 默认是跟Publish表的主键字段做的一对多外键关联
  • authors = models.ManyToManyField(to='Author') 数据库中并不会产生这个字段
  • author_detail = models.OneToOneField(to='AuthorDetail')一对一字段一般建在查询频率比较高的表中

3、同步到数据库

# run manage.py by task中
makemigrations
migrate # 终端中
python3 manage.py makemigrations
python3 manage.py migrate

​ 有四张表使我们建的,但app01_book_authors这张表是Djangoorm帮我们建的,是用来存储数据表和作者表的多对多表关系的。

4、手动录入测试数据,到了公司,运维那会有测试库

五、一对多字段的增删改

1、增,两种方式

# publish_id传数字
models.Book.objects.create(title='三国演义',price=189.99,publish_id=1) # publish直接传出版社对象
publish_obj = models.Publish.objects.filter(pk=2).first()
models.Book.objects.create(title='红楼梦',price=999.99,publish=publish_obj) # pubilsh_id字段是数据库中数据存在的字段
# publish字段是建表时的关联字段

2、改,两种方式

# 传数字的
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)

3、删

models.Publish.objects.filter(pk=2).delete()  # 默认都是级联更新 级联删除
# 会将Publish表中的id=2和Book表中的publish_id=2所对应的所有数据全部删除

六、多对多字段的增删改

1、增

# 要给主键为1的书籍添加作者
book_obj = models.Book.objects.filter(pk=1).first()
print(book_obj.authors) # 对象点击多对多虚拟字段 会直接跨到多对多的第三张表
book_obj.authors.add(1)
book_obj.authors.add(2,3) # 可以传多个数字 author_obj = models.Author.objects.filter(pk=1).first()
author_obj1 = models.Author.objects.filter(pk=2).first()
author_obj2 = models.Author.objects.filter(pk=3).first()
book_obj.authors.add(author_obj)
book_obj.authors.add(author_obj1,author_obj2) # 可以传对象,并且可以传多个
# add(),是给书籍添加作者,括号内既可以传数字也可以传对象,并且支持一次性传多个,逗号隔开即可

2、改

# 将主键为1的书籍对象 作者修改为2,3
book_obj = models.Book.objects.filter(pk=1).first()
book_obj.authors.set([2,]) # 必须传一个可迭代对象
book_obj.authors.set([2,3]) author_obj = models.Author.objects.filter(pk=1).first()
author_obj1 = models.Author.objects.filter(pk=2).first()
author_obj2 = models.Author.objects.filter(pk=3).first()
book_obj.authors.set([author_obj,])
book_obj.authors.set([author_obj, author_obj1, author_obj2])
# 将不要的删掉,要的留下来,没有的新增
# set()括号内,需要传一个可迭代对象,可以是多个数字组合,也可以是多个对象组合,但是不要混着用!!!

3、删,remove和clear

# remove()括号内既可以传数字,也可以传对象,并且支持传多个,逗号隔开即可
book_obj = models.Book.objects.filter(pk=1).first()
book_obj.authors.remove(3)
book_obj.authors.remove(1,2) author_obj = models.Author.objects.filter(pk=1).first()
author_obj1 = models.Author.objects.filter(pk=2).first()
author_obj2 = models.Author.objects.filter(pk=3).first()
book_obj.authors.remove(author_obj)
book_obj.authors.remove(author_obj1,author_obj2)
# clear() 将某本书跟作者的关系全部清空
book_obj = models.Book.objects.filter(pk=1).first()
book_obj.authors.clear() # 清空当前书籍与作者的所有关系,不需要传参数

七、基于对象的正反向查询

1、正向与反向的概念

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

查询技巧:正向查询按外键字段,反向查询按表名小写

2、基于对象的跨表查询(子查询:将一张表的查询结果当做另外一个查询语句的条件)

# 1.查询书籍id是1 的出版社名称
book_obj = models.Book.objects.filter(pk=1).first()
print(book_obj.publish) # 拿到的是一个publish对象
print(book_obj.publish.name)
print(book_obj.publish.addr) # 2.查询书籍id是2的作者姓名
book_obj = models.Book.objects.filter(pk=2).first()
print(book_obj.authors) # app01.Author.None
# 当遇到这种查询结果时,说明我们的查询方式并没有错,但还差一点点
# 这里是因为书籍与作者是多对多关系,所以一本书查到的作者可能有多个,所以要利用all拿出来
print(book_obj.authors.all())
res = book_obj.authors.all()
for r in res:
print(r.name) # 3.查询作者是jason的家庭住址
author_obj = models.Author.objects.filter(name='jason').first()
print(author_obj.author_detail.addr) # 4.查询出版社是东方出版社出版的书籍
publish_obj = models.Publish.objects.filter(name='东方出版社').first()
# 由出版社查书,反向查询,按表名小写book
print(publish_obj.book)
# 上面的查询方式是会报错的,说publish对象没有book属性,必须要加_set
print(publish_obj.book_set) # app01.Book.None
# 标志性的结果,说明缺少all
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()) # 6.查询电话号码是130的作者姓名
author_detail_obj = models.AuthorDetail.objects.filter(phone=130).first()
# 由作者详情查作者,反向查询,但是这里不需要加_set
print(author_detail_obj.author.name)
print(author_detail_obj.author.age)
"""
总结:当你反向查询的结果是多个的时候,就需要加_set,否则直接表明小写即可
"""
# 7.查询书籍id为1 的作者的电话号码
book_obj = models.Book.objects.filter(pk=1).first()
# 正向查询,查多个
author_list = book_obj.authors.all()
for author_obj in author_list:
print(author_obj.author_detail.phone)

3、基于双下划线的跨表查询(连表操作)

1、SQL语句中的连表操作:inner join,left join,right join,union

2、查询

# 1.查询jason作者的手机号
# 正向
res = models.Author.objects.filter(name='jason').values('author_detail__phone','author_detail__addr')
print(res)
# 反向
res1 = models.AuthorDetail.objects.filter(author__name='jason').values('phone')
print(res1) # 查询jason这个作者的年龄和手机号
# 正向
res = models.Author.objects.filter(name='jason').values('age','author_detail__phone')
print(res)
# 反向
res1 = models.AuthorDetail.objects.filter(author__name='jason').values('phone','author__age')
print(res1) # 查询手机号是130的作者年龄
# 正向
res = models.AuthorDetail.objects.filter(phone=130).values('author__age')
print(res)
# # 反向
res1 = models.Author.objects.filter(author_detail__phone=130).values('age')
print(res1) # 查询书籍id是1 的作者的电话号码
res = models.Book.objects.filter(pk=1).values('authors__author_detail__phone')
#res1 = models.Book.objects.filter(pk=1).values('外键字段1__外键字段2__外键字段3__普通字段')
print(res)
"""只要表里面有外键字段 你就可以无限制跨多张表""" # 查询出版社为北方出版社的所有图书的名字和价格
res = models.Publish.objects.filter(name='北方出版社').values('book__title','book__price')
print(res) # 查询北方出版社出版的价格大于19的书
res = models.Book.objects.filter(price__gt=19,publish__name='北方出版社').values('title','publish__name')
print(res)

八、聚合查询与分组查询

1、MySQL中的聚合函数:Sum,Max,Min,Avg,Count

2、聚合查询,aggregate

res = models.Book.objects.aggregate(s = Sum('price'))  # 起别名
res1 = models.Book.objects.aggregate(Avg('price'))
res2 = models.Book.objects.aggregate(Count('price'))
res3 = models.Book.objects.aggregate(Max('price'))
res4 = models.Book.objects.aggregate(Min('price'))
res5 = models.Book.objects.aggregate(Max('price'),Min('price'),Count('pk'),Avg('price'),Sum('price')) # 可以写多个

3、分组查询,annotate

# 统计每一本书的作者个数
from django.db.models import Max, Min, Count, Avg, Sum
res = models.Book.objects.annotate(author_num = Count('authors')).values('author_num','title')
print(res) # 统计出每个出版社卖的最便宜的书的价格
res = models.Publish.objects.annotate(mmp = Min('book__price')).values('name','mmp')
print(res) # 统计不止一个作者的图书
res = models.Book.objects.annotate(author_num=Count('authors')).filter(author_num__gt=1)
print(res)
"""
只要是queryset对象,就可以无限制的调用queryset对象的方法!!!
最最常用的就是对一个已经filter过滤完的数据,再进行更细化的筛选
"""

九、F与Q查询

1、F查询,之前查询等号后面的条件都是我们人为输入的,现在变成了需要从数据库中获取数据放在等号后面,F查询的本质就是从数据库中获取某个字段的值。

# 查询库存数大于卖出数的书籍
from django.db.models import F
res = models.Book.objects.filter(kucun__gt=F('maichu'))
print(res) # 将书籍库存数全部增加1000
models.Book.objects.update(kucun=F('kucun')+1000) # 把所有书名后面加上'新款'
from django.db.models.functions import Concat
from django.db.models import Value res = models.Book.objects.update(title=Concat(F('title'), Value('新款')))
models.Book.objects.update(title = F('title')+'新款') # 不能这么写

2、Q查询

from django.db.models import Q
# 查询书籍名称是三国演义或者价格是444.44
res = models.Book.objects.filter(title='三国演义',price=444.44) # filter只支持and关系
res1 = models.Book.objects.filter(Q(title='三国演义'),Q(price=444)) # 如果用逗号 那么还是and关系
res2 = models.Book.objects.filter(Q(title='三国演义')|Q(price=444)) # |表示or关系
res3 = models.Book.objects.filter(~Q(title='三国演义')|Q(price=444)) # ~表示not关系 # Q高级用法
q = Q() # Q是一个类,现实例化一个对象
q.connector = 'or' # 修改查询条件的关系 默认是and
q.children.append(('title__contains','三国演义')) # 以元组的形式往列表中添加筛选条件,q.children可以看做是一个列表
q.children.append(('price__gt',444)) # 往列表中添加筛选条件
res = models.Book.objects.filter(q) # filter支持你直接传q对象 但是默认还是and关系
print(res)

Django框架-模型层的更多相关文章

  1. Django框架-模型层3/数据传输/Ajax

    目录 一.orm查询优化 1.only与defer 2.select_related与prefatch_related 二.模型层choices参数 三.MTV与MVC模型 1.MVC 2.MTV 3 ...

  2. 【Django】模型层说明

    [Django模型层] 之前大概介绍Django的文章居然写了两篇..这篇是重点关注了Django的模型层来进行学习. ■ 模型定义 众所周知,Django中的模型定义就是定义一个类,其基本结构是这样 ...

  3. python 全栈开发,Day70(模板自定义标签和过滤器,模板继承 (extend),Django的模型层-ORM简介)

    昨日内容回顾 视图函数: request对象 request.path 请求路径 request.GET GET请求数据 QueryDict {} request.POST POST请求数据 Quer ...

  4. Django基础(2)--模板自定义标签和过滤器,模板继承 (extend),Django的模型层-ORM简介

    没整理完 昨日回顾: 视图函数: request对象 request.path 请求路径 request.GET GET请求数据 QueryDict {} request.POST POST请求数据 ...

  5. Django之模型层:表操作

    目录 Django之模型层:表操作 一.ORM简介 django测试环境搭建 Django终端打印SQL语句 二 单表操作 2.1 按步骤创建表 2.2记录 三.多表操作 1 创建模型 2 添加.删除 ...

  6. Django模板自定义标签和过滤器,模板继承(extend),Django的模型层

    上回精彩回顾 视图函数: request对象 request.path 请求路径 request.GET GET请求数据 QueryDict {} request.POST POST请求数据 Quer ...

  7. Django框架-路由层

    Django框架-路由层 一.URL配置(URLconf) 1.基本格式 from django.conf.urls import url urlpatterns = [ url(正则表达式, vie ...

  8. Django之模型层第一篇:单表操作

    Django之模型层第一篇:单表操作 一 ORM简介 ​ 我们在使用Django框架开发web应用的过程中,不可避免地会涉及到数据的管理操作(如增.删.改.查),而一旦谈到数据的管理操作,就需要用到数 ...

  9. 64、django之模型层(model)--建表、查询、删除基础

    要说一个项目最重要的部分是什么那铁定数据了,也就是数据库,这篇就开始带大家走进django关于模型层model的使用,model主要就是操纵数据库不使用sql语句的情况下完成数据库的增删改查.本篇仅带 ...

随机推荐

  1. 51Nod 1068 Bash游戏 V3 (这规律不好找)

    有一堆石子共有N个.A B两个人轮流拿,A先拿.每次拿的数量只能是2的正整数次幂,比如(1,2,4,8,16....),拿到最后1颗石子的人获胜.假设A B都非常聪明,拿石子的过程中不会出现失误.给出 ...

  2. 二分-B - Dating with girls(1)

    B - Dating with girls(1) Everyone in the HDU knows that the number of boys is larger than the number ...

  3. Java 在程序中输入输出

    本周主要学习了Java如何在程序中进行输入和输出,主要分为以下三种: 一.文本界面的输入与输出 1. 使用 javva.util.Scanner 类 2. 使用 in 及 out 二.图形界面的输入与 ...

  4. Java中new一个子类对象的同时并不会自动创建一个父类对象

    首先重申一个概念:子类会继承父类所有非私有成员变量和方法,包括父类的构造方法 当创建一个子类对象时,首先开辟内存,然后调用类的构造函数,这里的构造函数由两部分组成,一部分是从父类继承而来的父类的构造方 ...

  5. layer iframe 设置关闭按钮 和刷新和弹出框设置

    layer弹出层的关闭问题   就是在执行添加或修改的时候,需要将数据提交到后台进行处理,这时候添加成功之后最理想的状态是关闭弹出层并且刷新列表的数据信息,之前一直想实现这样,可一直没有成功,今天决定 ...

  6. Oracle的物理结构的三种文件

    .dbf数据文件,是用于存储数据库数据的文件,例如表中的记录,索引,数据字典信息等,可以通过系统数据字典DBA_DATA_FILES查看相关信息.与逻辑角度的表空间(并不是真正的文件)对应,一个表空间 ...

  7. 托管代码中调用c++本地代码

    c++本地动态连接库代码 #pragma once #include "stdafx.h" #ifdef PERSON_EXPORTS #define PERSON_API __d ...

  8. JavaScript 数组,字符串,函数

    数组 创建数组 利用 new 创建数组 var arr = new Array(); console.log(arr); // Array(0) 数组字面量创建 var arr = []; // 空数 ...

  9. ts中接口的用法

    ts中的接口主要的作用是: 对“对象”进行约束描述 对“类”的一部分行为进行抽象 一.属性接口 接口中可定义 确定属性.可选属性.任意属性.只读属性 1.确定属性 interface UserInfo ...

  10. Docker里面运行.net core

    详细可以参考微软官方文档:https://docs.microsoft.com/zh-cn/aspnet/core/host-and-deploy/docker/building-net-docker ...