ORM
orm名词解释: 对象关系映射,对象和关系之间的映射,使用面向对象的方式来操作数据库
关系模型和python对象之间的映射
table => classs 表映射为类
row => object 行映射为实例
cplumn => prorerty 字段映射为属性
Django ORM
对模型对象的CROUD,被Django ORM 转换成相应的SQL语句以操作不同的数据源
安装
$ pip install django == 2.2.7
项目准备
% django-admin startproject salary .
# 特别注意,后边的点要打上
创建应用
$ manage.py startapp employee
配置
打开salary/settings.py
配置文件
- 修改数据库配置
- 修改时区
- 注册应用
# 数据库配置
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'test',
'USER': 'bin',
'PASSWORD': 'bin',
'HOST': '127.0.0.1',
'PORT': '3306',
}
}
# 时区
TIME_ZONE = 'Asia/Shanghai'
# 注册应用
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'employee',
]
Django日志
也在setting.py
文件中。
# 最后一行添加代码
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers':{
'console': {
'class': 'logging.StreamHandler',
},
},
'loggers':{
'django.db.backends':{
'handlers': ['console'],
'level': 'DEBUG'
}
}
}
模型Model
字段类型
字段类 | 说明 |
---|---|
AutoField | 子等的整数字段 如果不指定,Django会为模型自动增加主键字段 |
BooleanField | 布尔值字段,True和False 对应表但空间Checkboxlnput |
NullBooleanField | 比BooleanField多一个null值 |
CharField | 字符串,max_length设定字符长度 对应表单控件Textlnput |
TextField | 大文本字段,一般超过4000个字符使用 对应用表单控件Textarea |
IntegerField | 整数字段 |
BigIntegerField | 更大整数字段,8字节 |
DecimalField | 使用python的Decimal实例表示十进制浮点数。max_digits总位数,decimal_places小数点后的位数 |
FloatField | Python的Float实例表示的浮点数 |
DateField | 使用Python的datetime.date实例表示的日期 auto_now=False每次修改对象自动设置为当前时间。 auto_now_add=False对象第一次创建时自动设置为当前时间。 auto_now_add、auto_now、default互斥 对应控件为TextInput,关联了一个Js编写的日历控件 |
TimeField | 使用Python的datetime.time实例表示的时间,参数同上 |
DateTimeField | 使用Python的datetime.datetime实例表示的时间,参数同上 |
FileField | 一个上传文件的字段 |
ImageField | 继承了FileField的所有属性和方法,但是对上传的文件进行校验,确保是一个有效的图片 |
EmailField | 能做Email检验,基于CharField,默认max_length=254 |
GenericIPAddressField | 支持IPv4、IPv6检验,缺省对应文本框输入 |
URLField | 能做URL检验,基于基于CharField,默认max_length=200 |
缺省主键
缺省情况下,Django的每一个Model都有一个名为id的AutoField字段
id = models.AutoField(primary_key=True)
如果显式定义了主键,这种缺省主键就不会被创建了。Python之禅中说“显式优于隐式”,所以,尽量使
用自己定义的主键,哪怕该字段名就是id,也是一种不错的选择。
字段选项
值 | 说明 |
---|---|
db_column | 表中字段的名称。如果未指定,则使用属性名 |
primary_key | 是否主键 |
unique | 是否是唯一键 |
default | 缺省值。这个缺省值不是数据库字段的缺省值,而是新对象产生的时候被填入的缺省值 |
null | 表的字段是否可为null,默认为False |
blank | Django表单验证中,是否可以不填写,默认为False |
db_index | 字段是否有索引 |
关系类型字段类
类 | 说明 |
---|---|
ForeignKey | 外键,表示一对多 ForeignKey(‘production.Manufacturer’) 自关联ForeignKey(‘self’) |
ManyToManyField | 表示多对多 |
OneToOneField | 表示一对一 |
一对多是,自动创建会增加_id后缀。
- 从一访问多,使用
对象.小写模型类_set
- 从一访问一,使用
对象.小写模型类
访问ID对象.属性_id
Model类
- 基类 django.db.models.Model
- 表名不指定默认使用
<appname>_<model_name>
。使用Meta类修改表名
由于Django不支持枚举类型字段,为了不引入额外的第三方库,将gender字段改为整型
from django.db import models
# Create your models here.
from django.db.models import Model
class Employee(models.Model):
class Meta:
db_table = 'employees'
# 用来装实例的
# 迁移用来建表
# Django会主动创建主键,id自增
# 如果class当中有主键,那么自动主键取消
object = models.Manager
emp_no = models.IntegerField(primary_key=True)
birth_date = models.DateField(null=False)
first_name = models.CharField(null=False,max_length=14)
last_name = models.CharField(null=False,max_length=16)
gender = models.SmallIntegerField(null=False)
hier_date = models.DateField(null=False)
def __repr__(self):
return "<Emp: {} {} {}>".format(
self.emp_no, self.first_name, self.last_name
)
__str__=__repr__
在项目根目录编写一个test.py, 内容如下
import os
import django
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'salary.settings')
django.setup()
from employee.models import Employee
emps = Employee.objects.all() # 结果集,本句不发起查询
print(type(emps))
print(*list(emps), sep='\n') # 所有员工
管理器对象
Django会为模型类提供一个objects对象,他是django.db.models.manager.Manager类型,用于与数据库交互。当定义模类的时候没有指定管理器,则Djamgo会为模型类提供一个objects的管理器。
如果在模型类中手动指定管理器后,Django不再提供默认的objects的管理器了。
管理器是Django的模型数据进行数据库查询操作的接口,Django应用的每个模型都至少拥有一个管理器。
用户也可以自定义管理器类,继承自django.db.models.manager.Manager,实现表级别控制。
查询
查询集
查询会返回结果的集,他是django.db.models.query.QuerySet类型。
它是惰性求值,和sqlalchemy一样。结果就是查询的集。
它是可迭代对象。
1、惰性求值:
创建查询集不会带来任何数据库的访问,直到调用方法使用数据时,才会访问数据库。在迭代、序列化、if语句中都会立即求值。
2、缓存:
每一个查询集都包含一个缓存,来最小化对数据库的访问。
新建查询集,缓存为空。首次对查询集求值时,会发生数据库查询,Django会把查询的结果存在这个缓
存中,并返回请求的结果,接下来对查询集求值将使用缓存的结果。
观察下面的2个例子是要看真正生成的语句了
- 没有使用缓存,每次都要去查库,查了2次库
[user.name for user in User.objects.all()]
[user.name for user in User.objects.all()]
- 下面的语句使用缓存,因为使用同一个结果集
qs = User.objects.all()
[user.name for user in qs]
[user.name for user in qs]
限制查询集(切片)
分页功能实现,使用限制查询集。
查询集对象可以直接使用索引下标的方式(不支持负索引),相当于SQL语句中的limit和offset子句。
注意使用索引返回的新的结果集,依然是惰性求值,不会立即查询。
qs = Employee.objects.all()[10:15]
# LIMIT 5 OFFSET 10
qs = Employee