Django模型层
Django模型层
- ORM简介
ORM使用
- 2.1 Django配置数据库信息
2.2 创建表
- 2.21 字段
- 2.22 参数
2.3 单表操作
2.31 创建记录
- 方式一:通过objects类
- 方式二:直接实例化类对象
2.32 查询记录
- 基于双下划线的模糊查询
- 2.33 修改记录
- 2.34 删除记录
2.4 多表操作
- 2.41 创建表记录
2.42 添加表记录
- 多对一/一对一添加表记录
- 多对多添加表记录
2.43 基于对象的跨表查询(子查询)
- 一对多
- 多对多
- 一对一
2.44 基于双下划线的跨表查询(join查询)
- 一对多
- 多对多
- 一对一
- 2.45 连续跨表查询
- 2.46 聚合查询
2.47 分组查询
- 单表分组查询
- 多表分组查询
2.48 F查询与Q查询
- F()查询
- Q()查询
Django模型层
这里所说的Django模型层,就是应用下面的models.py
中的东西
1. ORM简介
ORM功能就是将数据库SQL语句映射为python语句。相当于用python语法写出SQL语法的效果
实现过程:ORM –》pymysql –》mysql –》数据库
优点:数据库迁移更容易,底层不同类型数据库不会对python代码有影响
缺点:效率不如直接写SQL快,经过一个翻译的过程。只能对表操作,不能对数据库进行操作
2. ORM使用
2.1 Django配置数据库信息
在setting.py文件下找到DATABASES列表
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3', #代表数据库引擎
'NAME': "manytables", #代表相应的数据库(该数据库必须存在)
'USER':"root", #代表数据库用户名
'PASSWORD':"", #代表数据库密码
'HOST':"127.0.0.1", #代表数据库ip
'PORT':"3306", #代表数据库端口
}
}
如果我们要使用mysql,必须在setting.py或者是项目下init.py中导入PyMySQL
import pymysql
pymysql.install_as_MySQLdb()
2.2 创建表
在ORM中,创建表模型的方法是在models.py下面创建一个相应的类,用类来表示sql中的表
示例:
class Publish(models.Model): nid = models.AutoField(primary_key=True) name=models.CharField( max_length=32) city=models.CharField( max_length=32) email=models.EmailField() pub_date = models.DateField()
创建完表的类必须使用数据库迁移命令(在命令行中使用)
python manage.py makemigrations
python manage.py migrate
当修改表添加字段,再次使用命令会提示让我们提供一些值给已存在的记录
如下:
这时候我们需要给添加的字段设置默认值
例如:
read_num = models.IntegerField(default=0)
2.21 字段
SQL中的字段 | ORM字段 | 注意事项 |
---|---|---|
varchar,char字符型 | CharField | 必须有一个maxlength参数,用来表示最大字符数 |
int整数型 | IntegerField | 无 |
float浮点型 | FloatField | 必须提供两个参数,一个是max_digits 代表总位数,一个是decimal_places 代表小数位数 |
auto_increment 约束条件 | AutoField | 可选primary_key 参数设置为true时,将该字段设置为主键 |
MYSQL没有布尔类型,通常用tinyint(1) | BooleanField | 管理员用checkbox来表示 |
Date | DateField | 日期字段,可选参数auto_now 自动记录对象被保存时字段,auto_now_add 自动记录的是首次被创建的时间 |
注意:
+ 如果不指定主键,系统会自动添加主键
+ DateTimeField字段功能同Date
ORM新增字段 | 功能 |
---|---|
TextField | 管理员用textarea来表示 |
EmailFIeld | 检查邮箱合法性,不接受maxlength参数 |
ImageField | 存储图片,可选参数height_field 和width_field |
FileField | 存储文件,必须有upload_to 参数 |
略。。。
注意:每个表中都可以使用pk
字段代表主键
2.22 参数
参数 | 作用 |
---|---|
null | 该值为空,默认为false,如果将其设置为True,将会以Null存储 |
blank | 为True时,允许不填该字段,为False时就必须要填 |
default | 设置默认值,创建对象时调用 |
primary_key | 为True时,设置该字段为主键,Django默认会将一个IntegerField设置为主键 |
unique | 为true时,该字段中的值唯一 |
choices | 传入一个列表或元组,给字段提供选项,表单使用时会出现选择框,内容为choices中的内容 |
2.3 单表操作
表对象下的objects类封装了增删改查所有的功能
2.31 创建记录
方式一:通过objects类
Publish.objects.create(nid=1,name="ha",city="beijin",email="123@163.com")
方式二:直接实例化类对象
publish_obj = Publish(nid=1,name="ha",city="beijin",email="123@163.com")
publish_obj.save()
注意:实例化后必须使用save函数
2.32 查询记录
查询API | 功能 |
---|---|
all() | 查询所有结果,返回queryset对象 |
filter(kwargs) | 过滤,相当于SQL中when字段 |
get(kwargs) | 返回查询出有且只有一条的记录 |
exclude(*kwargs) | 返回与查询条件不匹配的记录 |
order_by(field) | 对查询结果排序(默认升序,传入字符串的字段前面加点.则表示降序排) |
reverse() | 对查询结果反向排序 |
count() | 返回获得的记录数 |
first() | 返回第一条记录 |
last() | 返回最后一条记录 |
exists() | 查看QuerySet是否包含数据,有则返回true(查询结果是否存在) |
values(field) | 相当于SQL中select和from之间的条件,查询QuerySet每个记录的指定字段 |
values_list(field) | 功能与values相似,返回的是元组,values返回的是列表 |
distinct() | 相当于SQL中的distinct关键字,去重(一般配合value使用) |
注意:如果要显示全部字段使用对象下的all()
函数,通常all()
函数可以省略
基于双下划线的模糊查询
传入变量名后缀__**
形式
后缀 | 示例 | 作用 |
---|---|---|
lt | Publish.objects.filter(nidlt=3) | 过滤出nid大于三的记录 |
gt | Publish.objects.filter(nidgt=3) | 过滤出nid小于三的记录 |
startswith | Publish.objects.filter(namestartswith=”li”) | 过滤出name字段以li 开头的记录 |
contains | Publish.objects.filter(namecontains=”li”) | 过滤出name字段包含li 字符串的记录 |
icontains | Publish.objects.filter(nameicontains=”li”) | 过滤出name字段包含li 字符串的记录(不区分大小写) |
in | Publish.objects.filter(namein=[“zs”,”ls”,”we”]) | 过滤出name字段等于zs 或ls 或we 的记录 |
year | Publish.objects.filter(pub_dateyear=2018) | 过滤出pub_date字段中年份为2018的记录(该字段必须为Date) |
mouth | Publish.objects.filter(pub_datemouth=2) | 过滤出pub_date字段中月份为2的记录(该字段必须为Date) |
range | Publish.objects.filter(nidrange=[3,5]) | 过滤出nid在3-5之间的记录 |
2.33 修改记录
过滤出的结果链式调用update()
函数Publish.objects.filter(nid = 1).update(name = "wb")
将nid为1的记录的name
字段修改为wb
2.34 删除记录
直接在过滤出的结果链式调用delete()
函数Publish.objects.filter(nid = 1).delete()
删除nid为1的记录
2.4 多表操作
多表操作分为三种情况:一对一,一对多,多对多
2.41 创建表记录
对于一对一情况,我们需要先创建一个字段,使用OneToOneField
建立关系,to
代表需要建立关系的表,如果不指定to_field
参数,默认绑定表的主键。必须要有一个on_delete
代表是否同步删除
示例:
class Author(models.Model):
nid = models.AutoField(primary_key=True)
name=models.CharField( max_length=32)
age=models.IntegerField()
# 与AuthorDetail建立一对一的关系
authorDetail=models.OneToOneField(to="AuthorDetail",on_delete=models.CASCADE)
class AuthorDetail(models.Model):
nid = models.AutoField(primary_key=True)
birthday=models.DateField()
telephone=models.BigIntegerField()
addr=models.CharField( max_length=64)
对于一对多情况,我们需要先创建一个字段,使用ForeignKey
建立关系,添加外键
示例:
class Book(models.Model):
nid = models.AutoField(primary_key=True)
title = models.CharField( max_length=32)
publishDate=models.DateField()
price=models.DecimalField(max_digits=5,decimal_places=2)
# 与Publish建立一对多的关系,外键字段建立在多的一方
publish=models.ForeignKey(to="Publish",to_field="nid",on_delete=models.CASCADE)
对于多对多情况,我们需要先创建是一个字段,使用ManyToManyField
来建立关系,
class Book(models.Model): nid = models.AutoField(primary_key=True) title = models.CharField( max_length=32) publishDate=models.DateField() price=models.DecimalField(max_digits=5,decimal_places=2) # 与Author表建立多对多的关系,ManyToManyField可以建在两个模型中的任意一个,自动创建第三张表 authors=models.ManyToManyField(to='Author',)
创建完表的类必须使用数据库迁移命令(在命令行中使用)
python manage.py makemigrations
python manage.py migrate
注意:
1.创建成功后,会在数据库里生成相应的表,表的格式为应用名__表名
例如:manytables__Book
而多对多产生的第三张表名为 应用名__表1名__表2名
2.外键字段,在表中会显示“外键_id”来命名
例如:publish_id
2.42 添加表记录
多对一/一对一添加表记录
因为有一个外键,添加表记录的方法有两种
方式一:直接给表的外键字段赋值Book.objects.create(nid=1,title="cprimer",publishDate="2012-12-3",price=30,publish_id=1)
Book表与Publish表为多对一的关系,publish_id为其外键
方式二:给外键对象赋值
publish_obj=Publish.objects.create(nid=1,name="ha",city="beijin",email="123@163.com")
Book.objects.create(nid=1,title="cprimer",publishDate="2012-12-3",price=30,publish=publish_obj)
直接将Publish对象赋值给publish
多对多添加表记录
多对多关系,每张表没有外键,但第三张表有其关系,这里用固定的API
添加多对多关系方法:对象名.绑定字段名.add()
注意:
1.使用在类中多对多方法时,不会给该表添加格外的字段,而是生成第三张表,来表示两者关系
2.我们可以使用添加多对多字段的表的对象,调用其下面的添加多对多字段名的add()方法
add()
方法解析,添加多对多记录
示例:
book表与author为多对多关系,且book表调用ManyToMany方法
book_obj.authors.add(author1_obj,author2_obj) #author1_obj,author2_obj为author对象
book_obj.authors.add(1,2,3) #1,2,3为对象id
remove()
,clear()
删除多对多记录
示例:
book_obj.authors.remove(2) #移除第三张表4,2关系
book_obj.authors.remove(1,2) #移除第三张表4,2关系和4,1关系
book_obj.authors.clear() #清空所有第三张表中所有与4相关联的记录
注意:
+ 从对象中访问外键对象,使用book_obj.publish
就可以从book_obj
对象访问publish
;而使用book_obj.pulish_id
就可以访问绑定的外键
+ 创建外键时,django会自动在外键名后面加_id
,例如创建一个外键名为publish
,而使用的外键字段是publish_id
2.43 基于对象的跨表查询(子查询)
正向查询:关联属性在A中,从A表查B表数据
逆向查询:关联属性在A中,从B表查A表数据
一对多
正向查询按字段,反向查询按表名小写_set
正向查询示例:
查询金瓶梅出版社的名字
book_obj=book.objects.filter(title="金瓶梅").first()
book_obj.publish.name
反向查询示例:
查询人民出版社出版过的书籍名称
publish_obj=Publish.objects.filter(name="人民出版社")
publish.book_set.all()
总结:关联属性在所查的表中时,直接使用基对象.关联对象.关联对象属性
来查询所需要的值;反之,使用基对象.关联对象_set.关联对象属性
来查询所需要的值
多对多
正向查询示例:
查询金瓶梅作者的名称
book_obj = Book.objects.filter(title="金瓶梅").first()
book_obj.authors.all().value('name')
反向查询示例:
找alex出版过的所有书籍名称
author_obj=Author.objects.filter(name="alex").first()
book_list=author_obj.book_set.all()
多对多与多对一查询方法一致
注意:book_obj.authors.all().value('name')
等同于book_obj.authors.value('name')
一对一
正向查询示例:
查找alex的手机号
alex=Author.objects.filter(name="alex").first()
alex.authordetail.telephone
查询手机号为110的作者的名字
AuthorDetail.objects.filter(telephone="110").first().author.name
总结:一对一查询无论正向查询还是反向查询,都直接查询对象即可
2.44 基于双下划线的跨表查询(join查询)
一对多
查询金瓶梅出版社的名字
方式一:正向查询Book.objects.filter(title="金瓶梅").values("publish__name")
方式二:反向查询Publish.objects.filter(book_title="金瓶梅").values("name")
多对多
查询金瓶梅作者的名称
方式一:正向查询Book.objects.filter(title="金瓶梅").values("authors__name")
方式二:反向查询author.objects.filter(book_title="金瓶梅").values("name")
一对一
查找alex的手机号
方式一:正向查询author.objects.filter(name="alex").values("authordetail__telephone")
方式二:反向查询authordetail.objects.filter(author_name="alex").value("telephone")
总结:
+ values()等同于select filter()等同于where
+ 如果想要查询的字段在关联表,则使用表名小写__字段
来进行跨表查询操作
2.45 连续跨表查询
查询手机号以110开头的作者出版过的所有书籍名称以及对应出版社名称
定基表:作者,书籍,出版社
方式一:book表为基表Book.objects.filter(authors__authordetail__telephone__startswith="110").value("name","publish__name")
注意:book表连接无关的authordetail表,需要连续跨表
方式二:以author表为基表Author.objects.filter(authordetail_telephone__startswith="110").value("book__title","book__publish__name")
总结:
连续跨表查询其实方法也一样,先定一个基表,然后找出基表与查询条件表的关系,跨表用__连接
2.46 聚合查询
查询平均价格,最大值,最小值
首先,必须先引入相关模块
from django.db.models import Avg,Max,Min, Count
Book.objects.all().aggregate(Avg("price"))
然后使用aggregate()
聚合函数
示例:
查询所有书籍的平均价格,最高价格,最低价格(average)Book.objects.all().aggregate(Avg("price"),Max("price"),Min("price"))
2.47 分组查询
单表分组查询
annotate()
为分组函数
示例:
查询每一个部门名称以及员工平均薪水Emp.objects.values("dep").annotate(avg_salary=Avg("salary"))
总结:单表模型.objects.values("group by的字段")。annotate(聚合函数("统计字段"))
多表分组查询
示例一:
查询每一个出版社的名称以及出版的书籍个数
Publish.objects.value("name").annotate(c=Count("book__title"))
默认显示name和c字段,如果要对分组后控制显示字段,则在后面加入value()
Publish.objects.value("nid").annotate(c=Count("book__title")).value("name","c")
注意:
+ 分组后可以显示任意字段,只是默认显示分组字段和聚合函数字段
+ value里面是什么,就按什么group by ,values()里面的内容相当于select和from中间的内容
+ 可以不使用value()
,使用all()
函数功能也相同,都是选择该表的字段(字段唯一),对表中的字段进行分组;
例如:查询每一个出版社的名称以及出版的书籍个数Publish.objects.all().annotate(c=Count("book_title")).values("name","email","c")
默认,all()
可以省略,即可写成Publish.objects.annotate(c=Count("book_title")).values("name","email","c")
2.48 F查询与Q查询
F()查询
F()就是将原来字段取到值,再次当参数传入
示例一:查找评论数大于阅读数的记录Book.objects.filter(comment_num__gt=F("read_num"))
不能直接用comment_num__gt=read_num这样操作,必须在右边加一个F()
示例二:将所有书籍价格提升十块钱Book.objects.all().update(price=F("price")+10)
不能直接用price+=10传入,必须用F()
Q()查询
查询名字为红楼梦,价格为100的书籍记录Book.objects.filter(title="红楼梦",price=100)
等同于Book.objects.filter(Q(title="红楼梦")&Q(price=100))
查询名字为红楼梦或价格为100的书籍记录Book.objects.filter(Q(title="红楼梦")|Q(price=100))
Q()可以连续嵌套Q(Q(A)|Q(B))|Q(C)
符号 | 名称 | 作用 |
---|---|---|
& | 与运算 | 两者都满足 |
</td>
<td> | 或运算 | |
~ | 非运算 | 取反运算 |
注意:
后面还可以跟关键字参数,但是关键字参数只能放在Q()后面Book.objects.filter(Q(title="红楼梦"),price=100)
还没有评论,来说两句吧...