一、ORM简介
如今几乎所有的软件开发过程中都会涉及到对象和关系数据库。在用户层面和业务逻辑层面,我们是面向对象的,而对象的信息保存在关系数据库中。按照原始SQL方式开发,程序员会在自己的业务逻辑代码中编写很多sql语句用来CRUD相关数据库数据,而这些代码通常都是极其相似或者重复。
ORM对象关系映射(object elational Mapping,简称ORM)模式是一种为了解决面向对象与关系数据库存在的互不匹配的现象的技术。简单的说,ORM是通过使用描述对象和书库之间映射的元数据,将程序中的对象自动持久化到关系数据库中。
它通常将一个类和一张表一一对应,类的每个实例对应表中的一条记录,类的每个属性对应表中的每个字段。ORM提供了对数据库的映射,不用直接编写sql代码,只需操作对象就能对数据库操作数据,让软件开发人员专注于业务逻辑的处理,提高了开发效率。当然ORM的操作是有限的,也就是ORM定义好的操作是可以完成的,一些复杂的查询操作是完成不了的(需要单独单发)。
二、Django中的ORM——Models
1. models定义
模型是关于您的数据的单一的、确定的信息来源。它包含您存储的数据的基本字段和行为。通常,每个模型映射到单个数据库表。
- 每个模型都是一个python类,它是django.db.models.Model的子类
- 模型的每个属性都代表一个数据库字段
- 综上所述,Django为您提供了一个自动生成的数据库访问API,详细见官方文档。
model与数据库结构对应关系图如下:
2.开发流程
(1)创建数据库
虚拟环境中安装MySql数据库模块
pip install pymysql
在Django_model [项目名] /Django_model/__init__py中书写
import pymysql
pymysql.install_as_MySQLdb()
修改settings.py文件
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql', # postgresql / mysql / sqlite3 / oracle
'NAME': 'test1', # 数据库名
'USER': 'root',
'PASSWORD': 'root',
'HOST': 'localhost', # 本地:localhost
'PORT': '3306', # 默认端口:3306
}
}
在settings.py的DATABASE前导入上述pymysql模块也可。
(2)构建工程代码
- 创建应用 python manage.py startapp [应用名]
- models.py 定义模型类 [数据表]
- settings.py中的 INSTALLED_APPS = [] 添加应用
- 生成迁移python manage.py makemigrations
- 执行迁移python manage.py migrate
- 使用模型
简单的例子:
这个样例模型定义了一个 Person
, 其拥有 first_name
和 last_name
:
from django.db import models
class Person(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
firstname 和 lastname 是模型的字段。每个字段都被指定为class属性,每个属性映射到数据库列。
字段类型将在后续内容讲解。
一旦你定义了你的模型,你需要告诉Django你将会使用这些模型(迁移或CRUD)。通过编辑你的设置文件和改变 INSTALLED_APPS 设置来添加包含你的 models.py 的模块的名称来实现这一点。
例如,如果您的应用程序的模型存在于模块myapp.models(为应用程序创建的包结构 manage.py startapp 脚本),INSTALLED_APPS** 应该增加模块内容:
INSTALLED_APPS = [
#...
'myapp',
#...
]
上面的Person模型在运行迁移python manage.py makemigrations以及python manage.py migrate后,会创建一个这样的数据库表:
CREATE TABLE myapp_person (
"id" serial NOT NULL PRIMARY KEY,
"first_name" varchar(30) NOT NULL,
"last_name" varchar(30) NOT NULL
);
3.models字段
模型中最重要的部分——以及模型中唯一需要的部分——是它定义的数据库字段列表。字段由class属性指定。注意不要选择与模型API冲突的字段名,如clean, save 或者 delete.
例子:
from django.db import models
class Musician(models.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
instrument = models.CharField(max_length=100)
class Album(models.Model):
artist = models.ForeignKey(Musician, on_delete=models.CASCADE)
name = models.CharField(max_length=100)
release_date = models.DateField()
num_stars = models.IntegerField()
(1)字段类型
Django配备了数十种内置的字段类型;您可以在模型字段引用中找到完整的列表。如果Django的内置函数不奏效,您可以轻松地编写自己的字段。常用字段类型如下:
· AutoField
自增的整形字段,必填参数primary_key=True,则成为数据库的主键,无该字段时,django自动创建。一个model不能有两个AutoField字段。
· IntegerField
一个整数类型,数值的范围是-214483648-314783647。
· FloatField
浮点数
· CharField
字符类型,对应mysql中的varchar类型,必须提供max_length参数,表示字符的长度。对于大量文本,请使用TextField。
· DateField
日期类型,日期格式为YYYY-MM-DD,相当于python中的datetime.date的实例。
参数:
- auto_now: 每次修改时修改为当前日期时间。
- auto_now_add: 新创建对象时自动添加当前日期时间。
- 上面两个参数和default参数是互斥的,不能同时设置。
· DatetimeField
日期时间字段,格式为YYYY-MM-DD HH:MM:[:ss[.uuuuuu][TZ]],相当于python中的atetime.datetime的实例。
· DecimalField
固定精度的十进制数字,在Python中由 Decimal实例表示。有两个必需的参数:
DecimalField.
max_digits
数字中允许的最大位数。请注意,此数字必须大于或等于decimal_places
。
DecimalField.
decimal_places
用数字存储的小数位数。
例如,要存储最大999
分辨率为两位小数的数字,可以使用:
models.DecimalField(..., max_digits=5, decimal_places=2)
所有字段类型详情可点击查询官网。
(2)字段选项
每个字段都接受一组特定于字段的参数。例如,CharField(及其子类)需要一个 max_length 参数,该参数指定用于存储数据的VARCHAR 数据库字段的大小。
对于所有字段类型,也有一组通用的参数。都是可选的。这里有一个对最常用的解释的快速总结:`
· null
如果是True,Django会将空置的值存储为 NULL。默认是False。创建的表字段即默认为not null。·
· blank
如果是True,这个字段是空白的。默认是False。
注意,这与null不同。null与数据库相关,而blank则是与验证相关的。如果一个字段有 blank=True ,表单验证就允许输入空值。如果一个字段有blank=False ,则需要字段。
· default
字段的默认值。这可以是一个值或者一个可调用的对象。如果每次创建新对象时都将调用callable。
· db_column
数据表字段名,默认值为model属性名。
· db_index
如果是True创建索引,默认是False。
· primary_key
如果True,此字段是模型的主键。
如果你没有指定你的模型中的任何字段的primarykey=True,Django会自动添加IntegerField来保存主键,所以除非你想要覆盖默认的主键行为,否则你不需要在任何字段上设置primarykey=True。
主键字段是只读的。如果您将主键的值更改为现存对象,然后保存它,那么将会在旧物件旁边创建一个新物件。例如:
from django.db import models
class Fruit(models.Model):
name = models.CharField(max_length=100, primary_key=True)
>>> fruit = Fruit.objects.create(name='Apple')
>>> fruit.name = 'Pear'
>>> fruit.save()
>>> Fruit.objects.values_list('name', flat=True)
<QuerySet ['Apple', 'Pear']>
· unique
如果是真的,这个字段必须在整个表中是唯一的。
· help_text
额外的“帮助”文本将显示在form小部件中。即使你的字段没有在表单上使用,它对文档也很有用。
· choices
2元组的可迭代(例如,列表或元组),用作此字段的选项。如果给出了这个,则默认表单小部件将是一个选择框而不是标准文本字段,并将限制对给定选项的选择。
(3)model Meta参数
模型元数据是“任何不是字段的数据”,比如排序选项(ordering),数据库表名(db_table)或者人类可读的单复数名称(verbose_name 和verbose_name_plural)。在模型中添加class Meta是完全可选的,所有选项都不是必须的。
class UserInfo(models.Model):
nid = models.AutoField(primary_key=True)
username = models.CharField(max_length=32)
class Meta:
# 数据库中生成的表名称 默认 app名称 + 下划线 + 类名
db_table = "table_name"
# 对象默认的顺序,它是一个字符串的列表或元组。每个字符串是一个字段名,前面带有可选的“-”
# 前缀表示倒序,前面没有“-”的字段表示正序。
Ordering = ['-order_date']
# admin中显示的表名称
verbose_name = '个人信息'
# verbose_name加s
verbose_name_plural = '所有用户信息'
# 联合索引
index_together = [
("pub_date", "deadline"), # 应为两个存在的字段
]
# 联合唯一索引
unique_together = (("driver", "restaurant"),) # 应为两个存在的字段
4.关联关系
Django提供了定义三种最常见的数据库关系类型的方法:多对一、多对多和一对一。
(1) 多对一
定义一个多对一的关联关系,使用 django.db.models.ForeignKey
类。就和其他 Field
字段类型一样,只需要在你模型中添加一个值为该类的属性。
ForeignKey需要一个位置参数:模型相关的类。
例如,如果一个“汽车”模型有一个“制造商”——也就是说,“制造商”生产多辆汽车,但每辆车都只有一个“制造商”——使用以下定义:
from django.db import models
class Manufacturer(models.Model):
# ...
pass
class Car(models.Model):
manufacturer = models.ForeignKey(Manufacturer, on_delete=models.CASCADE)
# ...
属性on_delete表示当删除关联表中的数据时,当前表与其关联的行的行为
models.CASCADE,删除关联数据,与之关联也删除
models.DO_NOTHING,删除关联数据,引发错误IntegrityError
models.PROTECT,删除关联数据,引发错误ProtectedError
models.SET_NULL,删除关联数据,与之关联的值设置为null(前提FK字段需要设置为可空)
models.SET_DEFAULT,删除关联数据,与之关联的值设置为默认值(前提FK字段需要设置默认值)
models.SET,删除关联数据,
a. 与之关联的值设置为指定值,设置:models.SET(值)
b. 与之关联的值设置为可执行对象的返回值,设置:models.SET(可执行对象)
(2)多对多
一个多对多的关联关系,使用 django.db.models.ManyToManyField
类。就和其他 Field
字段类型一样,只需要在你模型中添加一个值为该类的属性。
例如:如果 Pizza
含有多种 Topping``(配料) -- 也就是一种 ``Topping
可能存在于多个 Pizza
中,并且每个 Pizza
含有多种 Topping
--那么可以这样表示这种关系:
class Topping(models.Model):
# ...
pass
class Pizza(models.Model):
# ...
toppings = models.ManyToManyField(Topping)
对于多对多光联关系的两个模型,可以在任何一个模型中添加 ManyToManyField
字段,但只能选择一个模型设置该字段,即不能同时在两模型中添加该字段。
(3)一对一
使用 OneToOneField
来定义一对一关系。就像使用其他类型的 Field
一样:在模型属性中包含它。
当一个对象以某种方式“扩展”另一个对象时,这对该对象的主键非常有用。
- ForeignKey: 一对多, 将该属性定义到多的那一端
- OneToOneField: 一对一, 将该属性定义到任一端
- ManyToManyField: 多对多, 将该属性定义到两端