orm支持使用不同的数据库,可以通过方便的配置,切换使用不同的数据库。
django项目默认使用的是sqlite3小型数据库, 我们可以如下操作,把它修改为使用mysql数据库:
Django配置使用mysql数据库:修改settings.py中的DATABASES。
# Project01/setting.py DATABASES = { 'default': { # 'ENGINE': 'django.db.backends.sqlite3', # 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), # 配置mysql数据库 'ENGINE': 'django.db.backends.mysql', 'NAME': "db_django01", 'USER': "root", 'PASSWORD': "root", 'HOST': "localhost", 'PORT': 3306, } }
在python虚拟环境下安装mysqlPython包:
python2:
pip install mysql-python
python3:
pip install pymysql
在app01/__init__.py中加如下内容:
import pymysql pymysql.install_as_MySQLdb()
重新生成数据库表
1) 删除掉app01/migrations目录下所有的迁移文件
2) 重新执行:python manage.py makemigrations python manage.py migrate
确认是否已经生成了对应的数据库表。
字段类型和选项
在模型类中,定义属性,生成对应的数据库表字段:
属性名 = models.字段类型(字段选项)
属性名命名限制:
- 不能是python的保留关键字。
- 不允许使用连续的下划线,这是由django的查询方式决定的。
字段类型
使用时需要引入django.db.models包,字段类型如下:
AutoField:
自动增长的IntegerField,通常不需要指定,Django会自动创建属性名为id的自动增长属性。
BooleanField:
布尔字段,值为True或False
NullBooleanField:
支持Null、True、False三种值。
CharField (max_length=字符个数):
字符串 必须指定的参数: max_length 最大字符个数
TextField:
大文本字段,一般超过4000个字符时使用。
DateField:[auto_now=False, auto_now_add=False]:
日期
参数auto_now表示每次保存对象时,自动设置该字段为当前时间,用于"最后一次修改"的时间戳,它总是使用当前日期,默认为false。
参数auto_now_add表示当对象第一次被创建时自动设置当前时间,用于创建的时间戳,它总是使用当前日期,默认为false。
参数auto_now_add和auto_now是互斥的,不能在同时使用到一个类属性中。
TimeField:
时间,参数同DateField。
DateTimeField:
日期时间,参数同DateField。
IntegerField:
整数。在Django所支持的所有数据库中, 从 -2147483648 到 2147483647 范围内的值是合法的
DecimalField (max_digits=None, decimal_places=None):
十进制浮点数,用python中的Decimal实例来表示,适合用来保存金额。
必须指定参数: max_digits总位数,decimal_places小数位数。
例:最大值:99.99 -- DecimalField (max_digits=4, decimal_places=2)FloatField:
浮点数,用python中的float来表示,有误差。
FileField:
上传文件字段。
ImageField:
继承于FileField,对上传的内容进行校验,确保是有效的图片。
注意: 只要修改了表字段的类型,就需要重新生成迁移文件并执行迁移操作。
字段选项
通过选项实现对数据库表字段的约束:
选项 | 默认值 | 描述 | 是否要重新迁移修改表结构 |
---|---|---|---|
null | False | 如果为True,数据库中字段允许为空 | 是 |
unique | False | True表示这个字段在表中必须有唯一值 | 是 |
db_column | 属性名称 | 字段名,如果未指定,则使用属性的名称 | 是 |
db_index | False | 若值为True, 则在表中会为此字段创建索引。 查看索引:show index from 表名 | 是 |
primary_key | False | 若为True,则该字段会成为模型的主键字段,一般作为AutoField的选项使用 | 是 |
default | 默认值 | 否 | |
blank | False | True,html页面表单验证时字段允许为空 | 否 |
查询
每个模型类默认都有一个叫 objects 的类属性,它由django自动生成,类型为:
django.db.models.manager.Manager
,可以把它叫 模型管理器:>>> Employee.objects <django.db.models.manager.Manager object at 0x7fcfcdf67550>
objects模型管理器中提供了一些查询数据的方法:
objects管理器中的方法 返回类型 作用 模型类.objects.get() 模型对象 返回一个对象,且只能有一个:
如果查到多条数据,则报:MultipleObjectsReturned
如果查询不到数据,则报:DoesNotExist模型类.objects.filter() QuerySet 返回满足条件的对象 模型类.objects.all() QuerySet 返回所有的对象 模型类.objects.exclude() QuerySet 返回不满条件的对象 模型类.objects.order_by() QuerySet 对查询结果集进行排序 模型类.objects.aggregate() 字典,例如:
{'salary__avg': 9500.0}进行聚合操作
Sum, Count, Max, Min, Avg模型类.objects.count() 数字 返回查询集中对象的数目
对模型类作修改:
- 员工表新增了
hire_date
入职时间字段 - 员工表的
comment
备注信息字段可以为空 代码参考如下:
class Department(models.Model): """部门类""" # 部门名称:字符串类型(必须要指定最大长度) name = models.CharField(max_length=20) # 部门成立时间: 日期类型 create_date = models.DateField(auto_now_add=True) # modify_date = models.DateField(auto_now=True, null=True) def __str__(self): return self.name class Employee(models.Model): """员工类""" name = models.CharField(max_length=20) age = models.IntegerField() sex = models.IntegerField() # 工资:浮点类型(必须要指定两个选项) 999999.99 salary = models.DecimalField(max_digits=8, decimal_places=2) # 备注信息: 可以为空 comment = models.CharField(max_length=300, null=True, blank=True) # 员工入职时间 hire_date = models.DateField() # 一对多的外键:员工所属部门 department_id department = models.ForeignKey('Department') def __str__(self): return self.name
filter方法
filter方法用来实现条件查询,返回QuerySet对象,包含了所有满足条件的数据。 通过方法参数,指定查询条件:
模型类.objects.filter(模型类属性名__条件名 = 值)
判等: exact
例:查询id为1的员工
判等: exact
例:查询id为1的员工 (SQL: where id = 1)
Employee.objects.filter(id=1) Employee.objects.filter(id__exact=1)
模糊查询: contains / endswith / startswith
例:查询名字包含'马'的员工 (SQL: where name like '%马%')
Employee.objects.filter(name__contains='马')
例:查询名字以'军'结尾的员工 (SQL: where name like '%军')
Employee.objects.filter(name__endswith='军')
空查询: isnull
例:查询备注信息不为空的员工(SQL: where comment is not null)
Employee.objects.filter(comment__isnull=False)
范围查询: in
例:查询id编号为1或3或5的员工 (SQL: where id in (1,3,5))
Employee.objects.filter(id__in = [1,3,5])
. 比较查询: gt(greater than)、lt(less than)、gte、lte
例:查询age大于30的员工 (SQL: where age >= 30)
Employee.objects.filter(age__gte = 30)
. 日期查询: year
- mysql:
- date函数: date('2017-1-1')
- year函数: year(hire_date)
- python:
- date函数: date(2017,1,1)
例:查询2015年入职的员工 (SQL: where year(hire_date) = 2015)
Employee.objects.filter(hire_date__year=2015)
例:查询2014年1月1日后入职的员工 (SQL: where hire_date >= date('2014-1-1'))
from datetime import date
Employee.objects.filter(hire_date__gt=date(2014,1,1))
exclude方法
返回不满足条件的数据:
用法: 模型类.objects.exclude(条件)
例:查询id不为3的员工
exclude方法:返回不满足条件的数据
例:查询id不为3的员工 (SQL: where id != 3)
Employee.objects.exclude(id=3)
F对象
作用: 引用某个表字段的值, 生成对应的SQL语句
应用场景:比较表中的两个字段
例:查询语文分数大于数学分数的学生 成绩表.objects.filter(语文__gt=F('数学'))
用法: F('字段')
使用之前需要先导入:
from django.db.models import F
示例:
# 例:查询年龄大于id的员工信息(无实际意义) Employee.objects.filter(age__gt = F('id')) # 例:查询年龄大于4倍id编号的员工信息(无实际意义) Employee.objects.filter(age__gt = F('id')*4)
Q对象
作用: 组合多个查询条件,可以通过&|~(not and or)对多个Q对象进行逻辑操作。
用法: Q(条件1) 逻辑操作符 Q(条件2)
需要先导入:
from django.db.models import Q
示例:
例:查询id大于3且年龄大于30的员工信息。
Employee.objects.filter(id__gt=3, age__gt=30) Employee.objects.filter(Q(id__gt=3) & Q(age__gt=30))
例:查询id大于3或者年龄大于30的员工信息。
Employee.objects.filter(Q(id__gt=3) | Q(age__gt=30))
例:查询id不等于3员工信息。
Employee.objects.filter(~Q(id=3))
order_by方法
作用: 对查询结果进行排序, 默认升序
用法:
升序: 模型类.objects.order_by('字段名')
降序: 模型类.objects.order_by('-字段名')示例:
例:查询所有员工信息,按照id从小到大进行排序。
Employee.objects.all().order_by('id') Employee.objects.order_by('id')
例:查询所有员工信息,按照id从大到小进行排序。
Employee.objects.all().order_by('-id')
例:把id大于3的员工信息按年龄从大到小排序显示;
Employee.objects.filter(id__gt=3).order_by('-age')
aggregate方法
作用: 聚合操作,对多行查询结果中的一列进行操作,返回一个值。
用法: 模型类.objects.aggregate(聚合类('模型属性'))
- 常用聚合类有:Sum, Count, Max, Min, Avg等
- 返回值是一个字典, 格式: {'属性名__聚合函数': 值}
需先导入聚合类:
from django.db.models import Sum, Count, Max, Min, Avg
示例:
例:查询所有员工的人数。
Employee.objects.aggregate(Count('id'))
返回结果: {'id__count': 12}
例:查询所有员工的平均工资。
Employee.objects.aggregate(Avg('salary'))
返回结果: {'salary__avg': 9500.0}
count方法
- 作用:统计满足条件的对象的个数,返回值是一个数字
- 用法: 模型类.objects.count()
示例:
例:统计所有员工的人数。
Employee.objects.count()
例:统计id大于3的所有员工的人数。
Employee.objects.filter(id__gt=3).count()
查看ORM语句
可以通过查看mysql的日志文件,了解Django ORM 生成出来的sql语句。
配置查看mysql日志文件:
1、打开mysqld.cnf文件,打开68 69两行的注释:
sudo vi /etc/mysql/mysql.conf.d/mysqld.cnf
2、重启mysql服务
sudo service mysql restart
3、查看mysql日志文件的内容
sudo tail -f /var/log/mysql/mysql.log
tail命令: 默认会显示文件的末尾,会自动刷新显示文件最新内容。退出可按ctrl+c
QuerySet查询集
调用模型管理器的
all
,filter
,exclude
,order_by
方法会产生一个QuerySet,可以在QuerySet上继续调用这些方法,比如:Employee.objects.filter(id__gt=3).order_by('-age')
QuerySet可以作取下标操作, 注意:下标不允许为负数:
b[0]
- 取出QuerySet的第一条数据,
- 不存在会抛出
IndexError
异常
QuerySet可以作切片 操作, 切片操作会产生一个新的QuerySet,注意:下标不允许为负数。
QuerySet的get()方法
- 取出QuerySet的唯一一条数据
- QuerySet不存在数据,会抛出:
DoesNotExist
异常 - QuerySet存在多条数据,会抛出:
MultiObjectsReturned
异常
QuerySet的exists方法: QuerySet有一个exists方法,可以判断是否有数据。
QuerySet的特性:
- 惰性查询:只有在使用QuerySet中的数据时, 才会去查询数据库中的数据。
- 缓存:第一次遍历使用了QuerySet中的所有的对象(比如通过 列表生成式 遍历了所有对象),则django会把数据缓存起来, 第2次再使用同一个QuerySet时,将会使用缓存。注意:使用索引或切片引用查询集数据,将不会缓存,每次都会查询数据库。
增删改
- 调用一个模型类对象的
save
方法, 就可以实现数据新增或修改,id在表中存在为修改,否则为新增。 - 调用一个模型类对象的
delete
方法,就可以实现数据删除,会根据id删除。 - 改: 模型类.filter(条件).update(属性1=值1,属性2=值2..)
- 删: 模型类.filter(条件).delete()
一对多关联查询
假设在一对多关系中,一对应的类叫做一类,多对应的类叫做多类:
一、通过对象进行关联查询
用法:
由一类对象查询多类对象:
一类对象.多类名小写_set.all()
由多类对象查询一类对象:
多类对象.关联属性
示例:
# 查询部门id为1的所有员工 d = Department.objects.get(id=1) d.employee_set.all() # 一查多 # 查询id为1的员工所属的部门信息 e = Employee.objects.get(id=1) e.department # 多查一
二、通过模型类进行关联查询
用法:
通过多类的条件查询一类数据:
一类名.objects.filter(多类名小写__多类属性名__条件名=值)
通过一类的条件查询多类数据:
多类名.objects.filter(关联属性__一类属性名__条件名=值)
提示:会生成内连接语句进行查询, 条件名为
in
,gt
,isnull
等
关联查询
一、通过对象进行查询:
- 查询部门id为1的所有员工的信息。
d = Department.objects.get(id=1)
d.employee_set.all()
- 例:查询id为10的员工所属的部门信息。
e = Employee.objects.get(id=10)
e.department
二、通过模型类进行关联查询
示例:
例1:查询部门信息,要求部门中员工的名字包含'马'
select * from app01_department as d inner join app01_employee as e on d.id = e.department_id where e.name like '%马%'; Department.objects.filter(employee__name__contains='马')
例2:查询部门信息,要求部门中的员工的年龄大于30
select * from app01_department as d inner join app01_employee as e on d.id=e.department_id where age > 30 Department.objects.filter(employee__age__gt=30)
例3:查询部门为“研发部”的所有员工
select * from app01_employee as e inner join app01_department as d on e.department_id = d.id where d.name='研发部'; Employee.objects.filter(department__name__exact='研发部') Employee.objects.filter(department__name='研发部')
自关联
自关联是一种特殊的一对多的关系:
![](https://i-blog.csdnimg.cn/blog_migrate/3863f250f0361714cdc86b90dfa5218f.png)
自关联关联属性定义:
# 区域表自关联属性:特殊的一对多
关联属性 = models.ForeignKey('self')
添加区域模型类
class Area(models.Model):
"""区域类: 保存省份 城市 区县"""
# 区域名称
title = models.CharField(max_length=30)
# 关联属性:自关联 (表示上级区域)
parent = models.ForeignKey('self', null=True, blank=True)
def __str__(self):
return self.title