django的ORM框架
O是object,也就类对象的意思。
R是relation,翻译成中文是关系,也就是关系数据库中数据表的意思。
M是mapping,是映射的意思。
ORM框架会帮我们把类对象和数据表进行了一对一的映射,让我们可以通过类对象来操作对应的数据表。
ORM框架还可以根据我们设计的类自动帮我们生成数据库中的表格,省去了我们自己建表的过程。
django中内嵌了ORM框架,不需要直接编写SQL语句进行数据库操作,而是通过定义模型类,操作模型类来完成对数据库中表的增删改查和创建等操作。
ORM的优点
-
数据模型类都在一个地方定义,更容易更新和维护,也利于重用代码。
-
ORM 有现成的工具,很多功能都可以自动完成,比如数据消除、预处理、事务等等。
-
它迫使你使用 MVC 架构,ORM 就是天然的 Model,最终使代码更清晰。
-
基于 ORM 的业务代码比较简单,代码量少,语义性好,容易理解。
-
新手对于复杂业务容易写出性能不佳的 SQL,有了ORM不必编写复杂的SQL语句, 只需要通过操作模型对象即可同步修改数据表中的数据.
-
开发中应用ORM将来如果要切换数据库.只需要切换ORM底层对接数据库的驱动【修改配置文件的连接地址即可】
ORM 也有缺点
-
ORM 库不是轻量级工具,需要花很多精力学习和设置,甚至不同的框架,会存在不同操作的ORM。
-
对于复杂的业务查询,ORM表达起来比原生的SQL要更加困难和复杂。
-
ORM操作数据库的性能要比使用原生的SQL差。
-
ORM 抽象掉了数据库层,开发者无法了解底层的数据库操作,也无法定制一些特殊的 SQL。【自己使用pymysql另外操作即可,用了ORM并不表示当前项目不能使用别的数据库操作工具了。】
在settings.py中保存了数据库的连接配置信息,Django默认初始配置使用sqlite数据库。
我们可以通过以下步骤来使用django的数据库操作
1. 配置数据库连接信息 2. 在models.py中定义模型类 3. 生成数据库迁移文件并执行迁文件[注意:数据迁移是一个独立的功能,这个功能在其他web框架未必和ORM一块的] 4. 通过模型类对象提供的方法或属性完成数据表的增删改查操作
使用MySQL
pip install PyMySQ
__init__
from pymysql import install_as_MySQLdb install_as_MySQLdb() # 让pymysql以MySQLDB的运行模式和Django的ORM对接运行,作用是让Django的ORM能以mysqldb的方式来调用PyMySQL。
DATABASES
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'HOST': '127.0.0.1', # 数据库主机 'PORT': 3306, # 数据库端口 'USER': 'root', # 数据库用户名 'PASSWORD': '123', # 数据库用户密码 'NAME': 'student' # 数据库名字 } }
在MySQL中创建数据库
create database student; # mysql8.0默认就是utf8mb4; create database student default charset=utf8mb4; # mysql8.0之前的版本
关于解决
# 错误提示: django.db.utils.ProgrammingError: (1064, "You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED' at line 1") # 解决方案: # 在settings.py的DATABASE选项中每一个数据库连接加上OPTIONS选项配置. DATABASES = { # 'default': { # 'ENGINE': 'django.db.backends.sqlite3', # 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), # } "default":{ 'ENGINE':"django.db.backends.mysql", 'NAME': 'student', # 数据库名称 'USER': 'root', # 用户 'PASSWORD': '123', # 密码 'HOST': '127.0.0.1', # 地址 'PORT': '3306', # 端口 'OPTIONS':{ 'isolation_level':None } }, }
定义模型类
-
模型类被定义在"子应用/models.py"文件中。
-
模型类必须直接或者间接继承自django.db.models.Model类。
接下来以学生管理为例进行演示。[系统大概3-4表,学生信息,课程信息,老师信息]
在models.py 文件中定义模型类。
from django.db import models from datetime import datetime # 模型类必须要直接或者间接继承于 models.Model class BaseModel(models.Model): """公共模型[公共方法和公共字段]""" # created_time = models.IntegerField(default=0, verbose_name="创建时间") created_time = models.DateTimeField(auto_now_add=True, verbose_name="创建时间") # auto_now_add 当数据添加时设置当前时间为默认值 # auto_now= 当数据添加/更新时, 设置当前时间为默认值 updated_time = models.DateTimeField(auto_now=True) class Meta(object): abstract = True # 设置当前模型为抽象模型, 当系统运行时, 不会认为这是一个数据表对应的模型. class Student(BaseModel): """Student模型类""" #1. 字段[数据库表字段对应] SEX_CHOICES = ( (0,"女"), (1,"男"), (2,"保密"), ) # 字段名 = models.数据类型(约束选项1,约束选项2, verbose_name="注释") # SQL: id bigint primary_key auto_increment not null comment="主键", # id = models.AutoField(primary_key=True, null=False, verbose_name="主键") # django会自动在创建数据表的时候生成id主键/还设置了一个调用别名 pk # SQL: name varchar(20) not null comment="姓名" # SQL: key(name), name = models.CharField(max_length=20, db_index=True, verbose_name="姓名" ) # SQL: age smallint not null comment="年龄" age = models.SmallIntegerField(verbose_name="年龄") # SQL: sex tinyint not null comment="性别" # sex = models.BooleanField(verbose_name="性别") sex = models.SmallIntegerField(choices=SEX_CHOICES, default=2) # SQL: class varchar(5) not null comment="班级" # SQL: key(class) classmate = models.CharField(db_column="class", max_length=5, db_index=True, verbose_name="班级")//db_column是在数据库当中对应的字段,因为class是关键字不能作为变量名,可以理解为映射关系 # SQL: description longtext default "" not null comment="个性签名" description = models.TextField(default="", verbose_name="个性签名") #2. 数据表结构信息 class Meta: db_table = 'tb_student' # 指明数据库表名,如果没有指定表明,则默认为子应用目录名_模型名称,例如: users_student verbose_name = '学生信息表' # 在admin站点中显示的名称 verbose_name_plural = verbose_name # 显示的复数名称 #3. 自定义数据库操作方法 def __str__(self): """定义每个数据对象的显示信息""" return "<User %s>" % self.name
注意事项
1) 数据库表名
模型类如果未指明表名db_table,Django默认以 小写app应用名_小写模型类名 为数据库表名。
可通过db_table 指明数据库表名。
2) 关于主键
django会为表创建自动增长的主键列,每个模型只能有一个主键列。
如果使用选项设置某个字段的约束属性为主键列(primary_key)后,django不会再创建自动增长的主键列。
默认创建的主键列属性为id,可以使用pk代替,pk全拼为primary key
class Student(models.Model): # django会自动在创建数据表的时候生成id主键/还设置了一个调用别名 pk id = models.AutoField(primary_key=True, null=False, verbose_name="主键") # 设置主键
3) 属性命名限制
-
不能是python的保留关键字。
-
不允许使用连续的2个下划线,这是由django的查询方式决定的。__ 是关键字来的,不能使用!!!
-
定义属性时需要指定字段类型,通过字段类型的参数指定选项,语法如下:
属性名 = models.字段类型(约束选项, verbose_name="注释")
4)字段类型
说明 | |
---|---|
AutoField | 自动增长的IntegerField,通常不用指定,不指定时Django会自动创建属性名为id的自动增长属性 |
BooleanField | 布尔字段,值为True或False |
NullBooleanField | 支持Null、True、False三种值 |
CharField | 字符串,参数max_length表示最大字符个数,对应mysql中的varchar |
TextField | 大文本字段,一般大段文本(超过4000个字符)才使用。 |
IntegerField | 整数 |
DecimalField | 十进制浮点数, 参数max_digits表示总位数, 参数decimal_places表示小数位数,常用于表示分数和价格 Decimal(max_digits=7, decimal_places=2) ==> 99999.99~ 0.00 |
FloatField | 浮点数 |
DateField | 日期 参数auto_now表示每次保存对象时,自动设置该字段为当前时间。 参数auto_now_add表示当对象第一次被创建时自动设置当前。 参数auto_now_add和auto_now是相互排斥的,一起使用会发生错误。 |
TimeField | 时间,参数同DateField |
DateTimeField | 日期时间,参数同DateField |
FileField | 上传文件字段,django在文件字段中内置了文件上传保存类, django可以通过模型的字段存储自动保存上传文件, 但是, 在数据库中本质上保存的仅仅是文件在项目中的存储路径!! |
ImageField |
5)约束选项
选项 | 说明 |
---|---|
null | 如果为True,表示允许为空,默认值是False。相当于python的None |
blank | 如果为True,则该字段允许为空白,默认值是False。 相当于python的空字符串,“” |
db_column | 字段的名称,如果未指定,则使用属性的名称。 |
db_index | 若值为True, 则在表中会为此字段创建索引,默认值是False。 相当于SQL语句中的key |
default | 默认值,当不填写数据时,使用该选项的值作为数据的默认值。 |
primary_key | 如果为True,则该字段会成为模型的主键,默认值是False,一般不用设置,系统默认设置。 |
unique | 如果为True,则该字段在表中必须有唯一值,默认值是False。相当于SQL语句中的unique |
注意:null是数据库范畴的概念,blank是表单验证范畴的
6) 外键
在设置外键时,需要通过on_delete选项指明主表删除数据时,对于外键引用表数据如何处理,在django.db.models中包含了可选常量:
-
CASCADE 级联,删除主表数据时连通一起删除外键表中数据
-
PROTECT 保护,通过抛出ProtectedError异常,来阻止删除主表中被外键应用的数据
-
SET_NULL 设置为NULL,仅在该字段null=True允许为null时可用
-
SET_DEFAULT 设置为默认值,仅在该字段设置了默认值时可用
-
SET() 设置为特定值或者调用特定方法,例如:
from django.conf import settings from django.contrib.auth import get_user_model from django.db import models def get_sentinel_user(): return get_user_model().objects.get_or_create(username='deleted')[0] class UserModel(models.Model): user = models.ForeignKey( settings.AUTH_USER_MODEL, on_delete=models.SET(get_sentinel_user), )
商品分类表
id | category | |
---|---|---|
1 | 蔬菜 | |
2 | 电脑 | |
商品信息表
id | goods_name | cid |
---|---|---|
1 | 冬瓜 | 1 |
2 | 华为笔记本A1 | 2 |
3 | 茄子 | 1 |
-
-
当模型字段的on_delete=PROTECT,删除蔬菜,mysql自动检查商品信息表,有没有cid=1的记录,有则提示必须先移除掉商品信息表中,id=1的所有记录以后才能删除蔬菜。
-
当模型字段的on_delete=SET_NULL,删除蔬菜以后,对应商品信息表,cid=1的数据的cid全部被改成cid=null
-
当模型字段的on_delete=SET_DEFAULT,删除蔬菜以后,对应商品信息表,cid=1的数据记录的cid被被设置默认值。
数据迁移
将模型类定义表架构的代码转换成SQL同步到数据库中,这个过程就是数据迁移。
django中的数据迁移,就是一个类,这个类提供了一系列的终端命令,帮我们完成数据迁移的工作。
1)生成迁移文件
所谓的迁移文件, 是类似模型类的迁移类,主要是描述了数据表结构的类文件.
python manage.py makemigrations
2)同步到数据库中
python manage.py migrate
在django内部提供了一系列的功能,这些功能也会使用到数据库,所以在项目搭建以后第一次数据迁移的时候,会看到django项目中其他的数据表被创建了。其中就有一个django内置的admin站点管理。
# admin站点默认是开启状态的,我们可以通过http://127.0.0.1:8000/admin # 这个站点必须有个管理员账号登录,所以我们可以在第一次数据迁移,有了数据表以后,就可以通过以下终端命令来创建一个超级管理员账号。 python manage.py createsuperuse