Django模型M
模型M
一.Django ORM
- 创建项目 django-admin stareproject 项目名
- 创建应用 python manae.py startapp 应用名
- 连接数据 mysql -u root -p
- 创建数据库表 create databases 数据库名 charser=UTF8
二.Django配置使用mysql数据库
settings.py 配置下面的数据
1 | DATABASES = { |
在settings.py 同级的 __init__.py
下面配置 (看需求配置!!)
1 | import pymysql |
三.重定向
四.字段属性和选项
###模型类属性命名限制
不能是python的保留关键字。
不允许使用连续的下划线,这是有Django的查询方式决定的。
定义属性时需要制定字段类型,通过字段类型的参数指定选项,语法如下:
#####属性名 = models.字段类型选项
字段类型:
使用时候需要引入django.db.models 包
类型 | 描述 | 备注 |
---|---|---|
AutoField | 自动增长的IntegerField,通常不用指定,不指定时Django会自动创建属性名为id的自动增长属性 | |
BooleanField | 布尔字段,值为True或False type(True) ==bool类型 | |
NullBooleanField | 支持Null、True、False三种值 | |
CharField(max_length=最大长度) | 字符串。参数max_length表示最大字符个数 | |
TextField | 大文本字段,一般超过4000个字符使用 | |
IntegerField | 整数 | |
DecimalField( max_digits=None, decimal_places=None) |
十进制浮点数。参数manx_digits表示总位。参数decimal_places表示小数位。 | |
DeteField:( [auto_now=False, auto_now_add=False]) |
日期。 一:参数auto_now表示每次保存对象时,自动设置该子弹为当前时间“”最后一次修改”的时间戳,它总是使用当前日期,默认为false。 二:参数auto_now_add表示当对象第一次被创建是自动设置当前时间,用于创建的时间戳,它总是使用当前日期,默认为false. 三:参数 auto_now_add 和auto_now 是相互排斥的,组合将会发生错误。 |
|
TimeField | 时间,参数同DateField | |
DateTimeField | 日期时间,参数同DateField | |
FileField | 上传文件字段。 | |
ImageField | 继承与FileField,对上传的内容进行校验,确保是有效的图片。 |
选项:
通过选项实现对字符串字段的约束,选项如下:
选项名称 | 描述 |
---|---|
defaule | 默认值。设置默认值。 |
primary_key | 若为Ture,则该字段会成为模型的主键字段,默认值为False,一般作为Autofield的选项使用。 |
unique | 如果为True,这个字段在表中必须是唯一值,默认值是False. |
db_index | 若值为True,则在表中会为此字段创建索引,默认值是False. |
db_column | 字段的名称。如果未指定,则使用属性的名称。 |
null | 如果为True,表示允许为空,默认值是False |
blank | 如果为True,则该字段允许为空白,默认为False. |
对比:null是数据库范畴的概念,blank是后台管理页面表单验证范畴的。
经验:
当修改模型类之后如果添加的选项不影响表结构,则不需要重新做迁移,商品选项中default和blank不影响表结构。
五.查询
###1.Linux修改Mysql的日志文件:
让其产生mysql.log,及是mysql的日志文件,里面记录的对mysql数据库的操作记录。
使用下面的命令打开mysql的配置文件,去除68,69行的注释,然后保存。
1
sudu vi /etc/mysql/mysql.comf.d/mysqld.cnf
重启mysql服务,就会产生mysql的日志文件。
1
sudu service mysql restart
打开mysql日志文件。
1
/var/log/mysql/mysql.log 是mysql日志文件所在位置。
使用下面命令可以实现查看mysql的日志文件:
1
sudo tail -f /var/log/mysql/mysql.log
2.查询函数:
通过模型类:objects 属性可以调用如下函数,实现对模型类对应的数据表查询。
函数名 | 功能 | 返回值 | 说明 |
---|---|---|---|
get | 返回表中满足条件的一条且只能有一条数据。 | 返回值是一个模型类对象 | 参数中写查询条件。 1.如果查到多个数据,则抛出异常 MultipleObjectsReturned. 2.查询不到数据,则抛出异常:DoesNotExist. |
all | 返回模型类对应表格中的所有数据 | 返回值是ouerySet类型。 | 查询集 |
filter | 返回满足条件的数据。 | 返回值是OuerySer类型。 | 参数写查询条件 |
exclude | 返回不满足条件的数据。 | 返回值是ouerySet类型 | 参数写查询条件 |
order_by | 对查询结果进行排序 | 返回值是OuerySet类型 | 参数中写根据那个字段进行排序 |
get
查询一条信息
all
查询所有信息
filter
条件格式:
模型类属性名__条件名 = 值 (双下划线)
1.判等 exact
查询编号为1的图书。
bookInfo.objects.get(id=1)
bookInfo.objects.get(id__exact=1)
2.模糊查询
包含 contains
查询包含传的图书:
bookInfo.objects.filter(dtitle__contains=’传’)
以什么结尾 endswith
bookInfo.objects.filter(dtitle__endswith=’xxx’)
以什么开头 startswith
bookInfo.objects.filter(dtitle__ startswith=’xxx’)
#####3.空查询 isnull
bookInfo.objects.filter(btitle__isnull=False) 查询不为空的值
4.范围查询 in
5.比较查询
gt | 大于 |
---|---|
lt | 小于 |
gte | 大于等于 |
lte | 小于等于 |
6.日期查询
7.exclude 返回不满足条件的值。
与 filter 相反 exclude 返回不满足条件的值。
8.order_by 方法示例
作用:进行查询结果进行排序。
正序:字段名 .objects .all().order_by(‘字段’) 可以根据多个字段进行排序 升序从小到大
倒序:字段名 .objects .all().order_by(‘-字段’) 可以根据多个字段进行排序 降序从大到小 降序在字段前面加上 负号即可
查询条件加排序:字段名.objects.filter(字段__判断条件=‘判断内容’).order_by(‘排序字段’) 默认升序,加上 负号 降序。
总结:
只有get 返回一个模型的对象,其他查询条件返回的都是 查询集的对象。
多条件查询:
filter,exclude 可以多个条件查询。
条件之间是且的关系,
六.F对象
作用:用于类属性之间的比较。
解释F:之前我们的查询都是对一个值进行比较,而F对象适用于跟一个 属性之间进行比较。
使用之前需要导入:
1 | from django.db.models import F |
例:查询阅读量大于评论量图书的信息。
1 | 使用F把表内字段 包起来就行了。 |
例:查询图书阅读量大于2倍评论量的图书信息。
1 | 直接在后面写 * 2 就OK |
七:Q对象、
作用:用于查询是条件之间的逻辑。and or not ,可以对Q对象进行 &|~ 操作。
使用之前需要先导入:
1 | from django.db.models import Q |
Q | 所查询的对象需要被Q()包含 |
---|---|
| | 逻辑或 |
& | 和逻辑与 |
~ | 逻辑非 |
例:查询id大于3且阅读量大于30的图书信息。
1 | 普通方法 两个条件是逻辑与的关系。 |
例:查询id大于3或者阅读量大于30的图书信息。
1 | | 是逻辑或 用它连接Q的条件。 |
例:查询id不等于3的图书信息。
1 | ~ 不等于的意思, |
八.聚合函数
作用:对查询结果进行聚合操作。 导入的时候首字母为大写。
名称 | 作用 |
---|---|
sum | 总计 |
count | 统计数 |
avg | 平均值 |
max | 最大值 |
min | 最小值 |
aggregate:调用这个函数来使用聚合。返回一个值是字典。
使用之前需先导入聚合类: 用哪个导入那个
1 | from django.db.models import Sum,Count,Max,Min,Avg |
###aggregate函数
例:查询所有图书的数目。
1 | 必须制定某一个字段不能使用 * |
例:查询所有图书阅读量的综合。
1 | BookInfo.objects . aggregate( Sum ('bread') ) |
count 函数
返回值是一个数字。
作用:统计满足条件数据的数目。
例:统计所有图书的数目。
1 | 返回一个数字 返回所有读书的数量 |
例:统计id大于3的所有图书数目。
1 | 对数据进行筛选之后,在使用count函数。 |
查询相关函数!!
get:返回一个且只能有一条数据,返回值是一个对象,参数可以写查询条件。
all:返回模型类对应表的所有数据,返回值是QuerySet.
filter:返回满足套件的数据,返回值是QuerySet,参数可以写查询条件。
exclude:返回不满足条件的数据,返回值是QuerySer,参数可以写查询条件。
order_by:对查询结果进行排序返回值是QuerySet,参数中写排序的字段。
1 | from django.db.models import F,Q,Count,Max,Min |
- F对象:用于类属性之间进行比较。
- Q对象:用于条件之间的逻辑关系。
- aggregate:进行聚合操作,返回值是一个字典,进行聚合的时候,需要先导入聚合类。
- count:返回结果集中数据的目的,返回值是一个数字。
注意:
对一个QuerySet实例对象,可以据需调用上面的所有函数。
注意:
- 通过模型类实现关联查询时,要查那个表中的数据,就需要通过那个类来查。
- 写关联查询条件的时候,如果类中没有关系属性,条件需要对应类的名,如果类中有关系属性,直接写关系属性。
九.查询集
all 、 filter 、 exclude 、 order_by 调用这些函数会产生查询集,QuerySet类对象可以继续调用上限所有函数。
- 惰性查询:只有在实际使用查询集中的数据的时候才会发生对数据的真正查询。
- 缓存:当使用的是统计一个查询集的时候,第一次的时候就会发生实际数据库的查询,然后把结果缓存起来,之后在使用这个查询集的时候,使用的是缓存的结果。
限制查询集:
可以对一个查询集进行去下表或者切片操作来限制查询集的结果。
对一个查询集进行切片操作会产生一个新的查询集,下表不允许为负数。
取出查询集第一条数据的两种方式:
方式 | 说明 |
---|---|
b[0] | 如果 b[0] 不存在,就会抛出一个 IndexError异常。 |
b[0:1].get() | 如果 b[0:1].get() 不存在,就会抛出DoesNotExist异常。 |
exists:来判断一个查询集中是否有数据。 True False
十.模型类关系
- 一对多关系
- 列:图书类 —– 英雄类
- models.ForeignKey() 定义在多的类中。
- 多对多关系
- 列:新闻类 —- 新闻类型类 体育信息 国际新闻
- models.ManyToManyField() 定义在那个类中都行。
- 一对一关系。
- 列:员工基本信息类 —- 员工详细信息类 。 员工工号 。 员工被删除员工详细信息类还在,但是员工号不消失
- models.OneToOneField 定义在那个类都行。
##十一.关联查询
###一对多:
一对多的关系,例如员工跟部门。一个部门有多个员工。那么在django怎么建立这种表关系呢?
其实就是利用外键,在多的一方,字段指定外键即可。例如员工和部门,员工是多,所以在员工表直接部门即可。
1 | class Department(models.Model): //建立部门表 继承Model |
在设置外键时,需要通过on_delete 选项指明主表删除数据时,对于外键引用数据表如何处理,在Django.db.models 中包含了可选常量。
关联属性on_delete 选项的取值
models.CASCADE
此为默认值,级联删除,会删除关联数据1
department = models.ForeignKey('Department',on_delete=models.CASCADE)
models.PROTECT
只要存在关联数据就不能删除1
department = models.ForeignKey('Department', on_delete=models.PROTECT)
models.SET_NULL
删除数据后关联字段设置为NULL,仅在该字段允许为null
时可用(null=True
)
如果关联的字段不在该应用文件夹的model.py中,那么要写成这样
1
department = models.ForeignKey("(应用文件夹名).Department")
还有一个需要特别注意:
department = models.ForeignKey(“Department”,related_name=’employee’)时,通过部门查找员工的是用employee。如果不设置的话,是用默认的employee_set(类名的小写+_set)
一对多的查询
一个员工所属的部门(查出来的是对象):
a = Employee.objects.get(id=1)
b = a.department
一个部门的全部员工(查出来的是对象):
a = Department.objects.get(id=1)
b = a.employee_set.all()
多对多
多对多的关系,例如学生与社团。一个学生可以进多个社团,一个社团可以有多个学生。那么在django怎么建立这种表关系呢?
django建立多对多关系有两种方法。
方法一
1 | class Student(models.Model): //学生表 |
只需要在任意一方加上类似第6行的ManyToManyField就可以了。Django会自动为多对多关联关系创建一张表,用于两张表的联系。
那么查询呢?
1.一个社团的全部成员(查出来的是对象)
1 | c = Club.objects.get(id=1) |
2.一个成员的全部社团(查出来的是对象)
1 | s = Student.objects.filter(id=1) |
方法二
手动创建一张表关联联系。
1 | class Student(models.Model): |
一个学生加入的全部社团:
1 | a = Student.objects.get(id=1) |
一个社团的全部学生:
1 | a = Club.objects.get(id=1) |
在一对多关系中,一对应的类我们把它叫做一类,多对应的关系我们叫多类,我们把多类中定义的建立关联的类属性叫做关系属性。
十二.插入、更新和删除
调用一个模型类的对象save 方法的时候就可以实现对模型类对象数据表的插入和更新。
调用一个模型类对象的delete方法的时候就可以实现对模型类对应数据表的删除。
十三.自关联
自关联是一个特殊的一对多关系。
自关联模型,就是表中的某一列,关联了这个表中的另外一列。最典型的自关联模型就是地区表。省、市、县都在一张表里面。省的pid为null,市的pid为省的id,县的pid为市的id。
1 | class Area(models.Model): |
查询方法:
如果知道一个市,叫a市,想查他属于什么省。
1 | a = Area.objects.get(id=1) |
如果知道一个省,叫a省,想查他有什么市。
1 | a = Area.object.get(id=1) |
十四.管理器
BookInfo.objects.all() —-> objects 是什么东西呢?
答:objects 是Django 帮我自动生成的管理器对象,通过这个管理器可以实现对数据的查询。
objects 是 models.Manger 类的一个对象,自定义管理器之后Django不在帮我们生成默认的 objects 管理器。
- 自定义管理器类,这个类继承models.manger类。
- 再在集体的模型类李定义一个自定义管理器的对象。
自定义管理器的应用场景:
改变查询的结果集。
比如调用BookInfo.books.all() 返回的是没有删除的图书数据。
下面是一个自定义模型管理器:
1
2
3
4
5
6
7
8
9
10class BookInfoManager(models.Manager): //自定义方法使用manager
'''图书模型管理器'''
# 1. 改变查询结果集。
def all(self):
#1.调用父类的all,获取所有数据。
books = super().all() #返回QuerSet对象。
#2.对数据进行过滤。
books = books.filter(isDelete = False) //写过滤条件
#3.返回books
return books
添加额外方法。
管理器类定义一个方法帮我们擦欧总模型类对应的数据表。
使用 self.model() 就可以创建一个跟自定义管理器对应的模型类对象。
1
2
3
4
5
6
7
8
9
10
11
12
13
14class BookInfo(models.Model):
name = Model.CharField(max_length=20)
bpub_date = Model.
"""在表类里定义添加方法"""
def create_book(cls,name): //传一个形参
#1.创建一个图书对象。
obj = cls()
obj.name = name
#2.保存数据库。
obj.save()
#3.返回 obj
return obj这种方法定义在模型类里,模型类的内容就会很多,这种方法一般我们通常定义在模型管理器里。
封装函数:操作模型类对应的数据表(增删改查)都可以写在里面。
模型管理类与模型类之间的关系
十五.元选项
Django默认生成的表名:
应用名小写_模型类名小写
元选项:
需要在模型类中定义一个元类Meta,在里面定义一个雷属性 db_table 就可以只当表名称。
1 | class Meta: |
指定之后需要从新做迁移。
模型元选项
Options.abstract:
如果 abstract = True, 就表示模型是 抽象基类 (abstract base class).
Options.db_table:
该模型所用的数据表的名称:
db_table = ‘music_album’
Options.db_tablespace:
当前模型所使用的数据库表空间 的名字。
默认值是项目设置中的DEFAULT_TABLESPACE,如果它存在的话。
如果后端并不支持表空间,这个选项可以忽略。
get_latest_by
Options.get_latest_by
模型中某个可排序的字段的名称,比如DateField、DateTimeField或者IntegerField。
它指定了Manager的latest()和earliest()中使用的默认字段。
Options.managed
默认为True,意思是Django在migrate命令中创建合适的数据表,并且会在 flush 管理命令中移除它们。
换句话说,Django会管理这些数据表的生命周期。
如果是False,Django 就不会为当前模型创建和删除数据表。
Options.order_with_respect_to
按照给定的字段把这个对象标记为”可排序的“。这一属性通常用到关联对象上面,使它在父对象中有序。
相关联的对象也有两个方法, get_next_in_order() 和get_previous_in_order(),用于按照合适的顺序访问它们。
Options.ordering
对象默认的顺序,获取一个对象的列表时使用:
ordering = [‘-order_date’]
它是一个字符串的列表或元组。每个字符串是一个字段名,前面带有可选的“-”前缀表示倒序。
前面没有“-”的字段表示正序。使用”?”来表示随机排序
Options.permissions
设置创建对象时权限表中额外的权限。增加、删除和修改权限会自动为每个模型创建。
Options.proxy
如果proxy = True, 作为该模型子类的另一个模型会被视为代理模型。
Options.unique_together
用来设置的不重复的字段组合:
unique_together = ((“driver”, “restaurant”),)
它是一个元组的元组,组合起来的时候必须是唯一的。它在Django后台中被使用,
在数据库层上约束数据(比如,在 CREATE TABLE 语句中包含 UNIQUE语句)。
Options.index_together
用来设置带有索引的字段组合:
index_together = [
[“pub_date”, “deadline”],
]
十六.抽象基类
抽象基类在你将一些共同信息导入到多个其他模型的时候很有用。
你写你的基类,并在Meta类(元类)中设置abstract=True。该模型不用于生成任何数据库表。反而,当抽象基类用于其他模型的一个基类是,它的fields(字段)会被添加到那些子类中。
这个是错误的:抽象基类和其子类拥有同名的字段(Django会报异常)。
一个例子:
1 | from django.db import models |
上例中,Student模型有3个字段,name,age和home_group.CommonInfo模型不能用于普通Django模型,因为这是个抽象基类。CommonInfo不会生成一个数据库表或者拥有一个管理器,不能被实例化和直接存储。
对于许多用户来说,这种继承模型类型正是你想要的。它提供了在Python级别分解共同信息的一种方法,同时只根据数据库等级的子模型来生成一个数据库表。
###Meta继承:
创建抽象基类的时候,Django 会将你在基类中所声明的有效的 Meta 内嵌类做为一个属性。
如果子类没有声明自己的Meta类,它将继承父类的Meta类。如果子类想要扩展父Meta类,可以子类化。
例子:
1 | from django.db import models |
Django对抽象基类的Meta类做了一个调整:在安装Meta属性前,设置abstract=False.这意味着抽象基类的子类本身不会自动变成抽象类。当然,你可以通过从其他抽象基类继承的方法来生成一个抽象基类。你只要记住,每次明确地设置abstract=True。
对抽象基类而言,有些属性放在Meta内嵌类中没有意义。例如,包含db_table意味着所有子类(那些没有Meta内嵌类的子类)将会使用相同的数据库表,当然这也不是你想要的。
对于related_name 和 related_query_name要特别小心
当你正在ForeignKey或者MangToManyField中正使用related_name或者related_query_name时,你总要给字段(field)明确一个unique reverse name(唯一反向名称)和query time。这通常会在抽象基类中导致出现问题,因为Django会将基类字段添加进子类当中,而每个子类的字段属性值基本相同。这样,在使用ForeignKey或者ManyToManyField反向指定时,就无法确定指向哪个子类了。
为解决这个问题,当你(仅)在抽象基类中使用related_time或者related_query_name时,部分值应该包含’%(app_label)s’和‘%(class)s’。
‘%(class)s’会被子类名字取代;
‘%(app_label)s’会被子类所在App的名字取代。
举例:
假定有个app common/models.py:
1 | from django.db import models |
那么,common.ChildA.m2m字段的反向名称common_childa_related,
common_ChildB.m2m字段的反向名称为commom_childb_related;
rare app中,rare.ChildB.m2m字段的反向名称为rare_childb_related.
如果你没有在抽象基类中为某个关联字段定义related_name属性,那么默认的反向名称就是子类名称加上‘_set’,它能否正常工作取决于你是否在子类中定义了同名字段。
例如,上面代码中,如果去掉related_name属性,在ChildA中,m2m字段的反向名称就是childa_set;
而ChildB的m2m字段的反向名称就是childb_set.
###Multi-table继承 多表继承
这是Django支持的第二种继承方式。使用这种继承方式时,同一层级下的每个子model本身是一个model。
每个子model都有自己的数据库表,可单独查询与创建。继承关系在子model和它的每个父类之间采用链接方式。(通过自动创建的OneToOneField)。
1 | from django.db import models |
Place的所有字段在Restaurant中都可以使用,尽管数据驻留在不同的数据库表中。所以下面这些都是可能的:
Place.objects.filter(name=”Bob’s Cafe”)
Restaurant.objects.filter(name=”Bob’s Cafe”)
如果你有一个Place,同时也是Restaurant,你可以使用小写的model名称,从Place对象得到Restaurant对象:
p = Place.objects.get(id=12)
If p is restaurant object, this will give the child class:
p.restaurant
Restaurant:…
如果上例中p不是一个Restaurant,(它已经直接有Place对象创建或者是一些其他类的父类)。引用p.restaurtant将抛出Restaurant.DoesNotExist异常:
from myapp.models import Place,Restaurant
p=Place.objects.create(name=’Place’,addres=‘Place’)
p.restaurant
DoesNotExist:Place has no restaurant.
自动创建的Restaurant的OneToOneField字段链接Place如下:
place_ptr = models.OneToOneField(Placemon_delete=models.CASCADE,parent_link=Terue,)
你可以重载Restaurant的字段,通过在自己的OneToOneField中申明parent_link=True。
###Meta和多表继承
在多表继承中,子类继承父类的Meta内嵌类没什么不清楚的。所有Meta选项已经对父类起作用了,再次使用只会起反作用(这与使用抽象基类的情况正好相反,因为抽象基类并没有属于它自己的内容)
待续。。。。
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 jaytp@qq.com