ORM介绍:object relational mapping 对象关系映射
1> 把面向对象中的类和数据库表一一对应,通过操作类和对象,对数据表实现数据操作,不需要写sql,由orm框架生成。
2> Django实现了ORM的一个框架,在项目与数据库之间起桥梁作用。
3> django数据库开发步骤如下:
a 在models.py定义模型类
b 生成迁移文件: python manage.py makemigrations -> 在migrations文件夹生成0001_intial.py
c 执行迁移生成数据库(默认会用sqite3数据库,生成数据库名为:db.sqlite3)
python mange.py migrate -> 在数据库中生成对应的数据 test01_department 等
d 通过模型类和对象,对数据进行增删改查
模型类设计:
1> 在应用models.py 中编写模型类,必须继承于models.Model类
2> 在模型类中,定义属性,生成对应的数据库表字段
属性名 = models.字段类型(字段选项)
3> 字段类型(初步了解,models包下的类):只要修改了类型,就需要重新迁移
- AutoField: 自动增长,通常不需要指定,django自动创建名为id的自动增长属性
- CharField: 字符串,必须指定的参数: max_length 最大字符个数
- TextFiled: 大文本字段,一般超过4000个字符
- IntegerField: 整形
- BooleanField: 布尔,支持Null,True
- NullBooleanField: 支持Null,True,False
- DateFiled: [auto_now=False, auto_now_add=False]
-
- auto_now 表示自动设置该字段为最后一次修改的时间,默认为False
- auto_now_add 表示自动设置该字段为创建时的时间,默认为False
- 两者互斥,不能同时使用
- DateTimeField: 日期时间
- DecimalFiled(max_digits=None, decimal_places=None):
-
- 十进制浮点数,适合用于保存金额,精度较高
- 必须指定参数,max_digits总位数,decimal_places小数位数
- FloatField: 浮点数,有误差
- FileField: 上传文件字段
- ImageField: 继承与FileFiled,对上传的内容进行校验,确保是有效地图片
- ForeignKey: 外键,建立一对多关系
4> 字段选项:通过选项实现对字段的约束
选项 |
默认值 |
描述 |
是否要重新迁移修改表结构 |
null |
False |
如果为True,数据库中字段允许为空 |
是 |
unique |
False |
True表示这个字段在表中必须有唯一值 |
是 |
db_column |
属性名称 |
字段名,如果未指定,则使用属性的名称 |
是 |
primary_key |
False |
若为True,则该字段会成为模型的主键字段,一般作为AutoField的选项使用 |
是 |
default |
- |
默认值 |
否 |
blank |
False |
True,html页面后台填写表单验证时字段允许为空 |
否 |
editable |
True |
如果设为False, 这个字段将不会出现在管理后台 |
否 |
choices |
- |
True,html页面表单验证时字段允许为空 |
否 |
choices-下拉列表:
choices_sex = (
(0, '男'),
(1, '女'),
)
sex = models.IntegerField(default=0, choices=choices_sex)
5> 元类class Meta的使用:
class Meta:
# 修改表名(需要迁移)
db_table = 'department'
# 修改后台的显示的表名
verbose_name = '部门'
# 去除复数形式
verbose_name_plural = verbose_name
修改和添加类:
from test01.models import *
from datetime import date
d = Department()
d.name = ‘人事部’
d.create_date = date(2019, 1, 1)
d.save()
d.id = None # 修改id创建新的数据
d.save()
d.id = 2
d.delete() # 删除id=2
模型管理器:
1> 在django创建对象时,都会默认创建一个object属性,是一个manage类,有以下几种方法:
objects管理器中的方法 |
返回类型 |
作用 |
模型类.objects.get() |
模型对象 |
返回一个对象,且只能有一个:
如果查到多条数据,则报:MultipleObjectsReturned
如果查询不到数据,则报:DoesNotExist |
模型类.objects.all() |
QuerySet |
返回所有的对象 |
模型类.objects.filter() |
QuerySet |
返回满足条件的对象 |
模型类.objects.exclude() |
QuerySet |
返回不满条件的对象 |
模型类.objects.order_by() |
QuerySet |
对查询结果集进行排序 |
模型类.objects.aggregate() |
字典,例如:
{‘salary__avg’: 9500.0} |
进行聚合操作
Sum, Count, Max, Min, Avg |
模型类.objects.count() |
数字 |
返回查询集中对象的数目 |
get(), all() 和 employee_set.all()方法:
d = Department.objects.get(id=1)
print(d.name)
----------------------------------------------------------------------
>>> from test01.models import *
>>> d = Department.objects.all()
>>> d
[, ]
>>> e = Employee()
>>> e.name = '张三'
>>> e.age = 20
>>> e.sex = 0
>>> e.salary = 100000
>>> e.comment = '无'
>>> e.department = Department.objects.get(id=1) # 设置外键
>>> e.save()
>>> e.id = None
>>> e.name = '李四'
>>> e.save()
>>> d = Department.objects.get(id=1) # 重复设置外键
>>> d.employee_set.all() # employee_set 为django一对多的时候自动生成的属性
[, ]
----------------------------------------------------------------------
# 根据员工查部门
>>> e = Employee.objects.get(id=1)
>>> e.department
增删改:
Employee.objects.filter(id=1).delete()
Employee.objects.filter(id=1).update(name=‘行政部')
条件查询:
1> 判等:exact
# 例:查询id为1的员工
select * from test01_employee where id = 1;
Employee.objects.filter(id__exact=1)
Employee.objects.filter(id=1)
2> 模糊查询:contains,endswith/startswith
# 查询包含马的员工
select * from test01_employee where name = “%马%";
Employee.objects.filter(name__contains=‘马’)
3> 空查询:isnull
# 查询comment 不为空
select * from test01_employee where comment is not null;
mployee.objects.filter(comment__isnull=False)
4> 范围查询:in
# 查询id为1,3,5
select * from test01_employee where id in (1, 3, 5);
Employee.objects.filter(id__in=(1, 3, 5))
5> 比较查询:gte(>=), lte(<=), gt(>), lt(<)
# 查询年龄大于等于30
mployee.objects.filter(age__gte=30)
6> 日期查询: year、month、day、week_day、hour、minute、second
# 查询入职年份为2015
select * from test01_employee where year(hire_date) = 2015;
Employee.objects.filter(hire_date__year=2015)
# 查询入职年份在2015-1-1以后
select * from test01_employee where hire_date >= date(2015-1-1);
from datetime import date
Employee.objects.filter(hire_date__gte=date(2015, 1, 1))
7> exclude:
# 查询id 不等于 1
select * from test01_employee where id != 1;
Employee.objects.exclude(id=1)
关联查询:
1> 通过对象:
a. 一对多 departement.employee_set.all()
b. 多对一 employee.department
2> 通过模型管理器:
# 查询部门信息,要求部门中员工名字包含马
select * from test01.department as d inner join test01.employee as e
on d.id = e.department_id where e.name like ‘%马%’;
Department.objects.filter(employee__name__contains='马’)
>>> , ]>
# 查询部门为研发部的所有员工信息
select * from test01.department as d inner join test01.employee as e
on d.id = e.department_id where d.name = '研发部’
Employee.objects.filter(department__name__exact = '研发部’)
>>> , , ]>
F对象:用于比较表中两个字段
# 查询age 大于四倍 id
from django.db.models import F
Employee.objects.filter(age__gt=F('id') * 4)
Q对象:对查询条件进行与或非(&|~)的逻辑操作,多个条件
# 查询年龄大于30 且 id 大于3
from django.db.models import Q
select * from test01_employee where id > 3 and age > 30;
Employee.objects.filter(id__gt=3, age__gt=30)
Employee.objects.filter(Q(id__gte=3)&Q(age__gte=30))
# 查询id不等于3
Employee.objects.filter(~Q(id=3)) -> 波浪线
order_by 方法:排序方法,降序’-属性名’
# 统计id 大于等于3,降序排列
select * from test01_employee where id > 3 order by age desc; -> [asc升序]
Employee.objects.filter(id__gt=3).order_by('-age')
aggregate方法:聚合操作,对多行查询结果的一列进行操作
1> 常用聚合类Sum, Count, Max, Min, Avg,返回字典{‘属性名__聚合函数’: 值}
2> from django.db.models import Count, Avg
# 查询总人数
select count(*) from test01_employee;
Employee.objects.aggregate(Count('id’))
>>> {'id__count': 10}
# 查询工资平均数
select avg(salary) from test01_employee;
Employee.objects.aggregate(Avg('salary’))
>>> {'salary__avg': 9600.0}
count()方法:统计总数,返回一个数值
# 查询id大于等于3的人数
select count(*) from test01_employee where id >= 3;
Employee.objects.filter(id__gte=3).count()
QuerySet 查询集:
1> 为一个数列,下标不能够为负,可以进行切片操作,datas[0:1:-1]
2> 拥有get(),同objects管理器相同。
3> 拥有exists(),判断数列中是否有数据
4> 惰性查询:创建QuerySet的时候不会马上查询数据库,当访问数据的时候才会发起查询操作。
datas = Department.objects.all() # 不会查询
5> 缓存:当首次查询时,会缓存,再次查询时会使用之前查询的数据, 但是使用索引或者切片操作,就不会缓存
datas = Department.objects.all()
# 首次遍历,缓存数据
[deps.name for deps in datas]
# 不会查询数据库
[deps.name for deps in datas]
datas = Department.objects.all()
# 会查询数据库
datas[0]
# 会查询数据库
datas[0]
自关联:查询父级和子级目录
class Area(models.Model):
title = models.CharField(max_length=20)
parent = models.ForeignKey(‘self’, on_delete=models.CASCADE, null=True, blank=True)
def __str__(self):
return self.title
+------+-----------------------------------------------+-----------+
| id | title | parent_id |
+------+-----------------------------------------------+-----------+
| 1 | 中国 | NULL |
| 2 | 北京市 | 1 |
| 3 | 天津市 | 1 |
+------+-----------------------------------------------+-----------+
from app01.models import *
a = Area.objects.get(id=232)
# 获得父级
a.parent.title >>> ‘广东省’
# 获得子级
a.area_set.all() >>> ….