乔克视界 乔克视界
首页
  • 运维
  • 开发
  • 监控
  • 安全
  • 随笔
  • Docker
  • Golang
  • Python
  • AIOps
  • DevOps
  • 心情杂货
  • 读书笔记
  • 面试
  • 实用技巧
  • 博客搭建
友链
关于
收藏
  • 分类
  • 标签
  • 归档

乔克

云原生爱好者
首页
  • 运维
  • 开发
  • 监控
  • 安全
  • 随笔
  • Docker
  • Golang
  • Python
  • AIOps
  • DevOps
  • 心情杂货
  • 读书笔记
  • 面试
  • 实用技巧
  • 博客搭建
友链
关于
收藏
  • 分类
  • 标签
  • 归档
  • Docker

  • Golang

  • AIOps

  • Python

    • 基础知识

    • Django框架

      • Django之框架
      • Django之ORM详解
        • 一、ORM 介绍
          • 1、ORM 概念
          • 2、ORM 优势
          • 3、ORM 劣势
          • 4、ORM 总结
        • 二、Django 中的 ORM
          • 1、Django 项目使用 MySQL 数据库
          • 2、Django 中的 Model
          • 3、例子
        • 三、Django 中 ORM 常用字段和参数
          • 1、常用字段
          • 2、字段集合
          • 3、自定义字段
          • 4、ORM 字段与数据库实际字段的对应关系
          • 5、字段参数
          • 6、时间字段参数
          • 7、关系字段
          • 7.1、ForeignKey
          • 7.2、OneToOneField
          • 7.3、ManyToManyField
          • 7.4、元信息
      • Django之操作ORM
      • Django之操作ORM例子
      • Django之路由系统
      • Django之跨站请求伪造
      • Django之Cookie和Session
      • Django之CBV和FBV
      • Django之中间件
      • Django之用户认证系统
      • Django之Form组件
      • Django之Ajax
      • Django之模板语言
      • Django之URL分发
      • Django中的缓存
      • Models迁移原理
      • 自定义组件Xadmin
      • Markdown 富文本插件
      • 手写一个验证码
    • 其他

  • DevOps

  • 专栏
  • Python
  • Django框架
乔克
2025-07-19
目录

Django之ORM详解

# 一、ORM 介绍

# 1、ORM 概念

对象关系映射(Object Relational Mapping,简称 ORM)模式是一种为了解决面向对象与关系数据库存在的互不匹配的现象的技术。

简单的说,ORM 是通过使用描述对象和数据库之间映射的元数据,将程序中的对象自动持久化到关系数据库中。

ORM 在业务逻辑层和数据库层之间充当了桥梁的作用。

# 2、ORM 优势

(1)、ORM 解决的主要问题是对象和关系的映射。它通常把一个类和一个表一一对应,类的每个实例对应表中的一条记录,类的每个属性对应表中的每个字段。

(2)、ORM 提供了对数据库的映射,不用直接编写 SQL 代码,只需像操作对象一样从数据库操作数据。

(3)、让软件开发人员专注于业务逻辑的处理,提高了开发效率。

# 3、ORM 劣势

ORM 的缺点是会在一定程度上牺牲程序的执行效率。

# 4、ORM 总结

ORM 只是一种工具,工具确实能解决一些重复,简单的劳动。这是不可否认的。

但我们不能指望某个工具能一劳永逸地解决所有问题,一些特殊问题还是需要特殊处理的。

但是在整个软件开发过程中需要特殊处理的情况应该都是很少的,否则所谓的工具也就失去了它存在的意义。

# 二、Django 中的 ORM

# 1、Django 项目使用 MySQL 数据库

(1)、在 Django 项目的 settings.py 文件中,配置数据库连接信息

DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.mysql",
        "NAME": "你的数据库名称",  ## 需要自己手动创建数据库
        "USER": "数据库用户名",
        "PASSWORD": "数据库密码",
        "HOST": "数据库IP",
        "POST": 3306
    }
}
1
2
3
4
5
6
7
8
9
10

(2)、在 Django 项目的init.py 文件中写如下代码,告诉 Django 使用 pymysql 模块连接 MySQL 数据库

import pymysql
pymysql.install_as_MySQLdb(
1
2

# 2、Django 中的 Model

在 Django 中 model 是你数据的单一、明确的信息来源。它包含了你存储的数据的重要字段和行为。通常,一个模型(model)映射到一个数据库表。

基本情况:

  • 每个模型都是一个 Python 类,它是 django.db.models.Model 的子类。
  • 模型的每个属性都代表一个数据库字段。
  • 综上所述,Django 为您提供了一个自动生成的数据库访问 API,详询官方文档链接 (opens new window)。

如下图:

ba067d9705eedbf520cdc151698d717e MD5

# 3、例子

下面这个例子定义了一个  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)
1
2
3
4
5

**first_name **和  last_name  是模型的字段。每个字段被指定为一个类属性,每个属性映射到一个数据库列。

上面的  Person  模型将会像这样创建一个数据库表:

CREATE TABLE myapp_person (
    "id" serial NOT NULL PRIMARY KEY,
    "first_name" varchar(30) NOT NULL,
    "last_name" varchar(30) NOT NULL
);
1
2
3
4
5

说明:

  • 表 myapp_person 的名称是自动生成的,如果你要自定义表名,需要在 model 的 Meta 类中指定  db_table  参数,强烈建议使用小写表名,特别是使用 MySQL 作为后端数据库时。
  • id 字段是自动添加的,如果你想要指定自定义主键,只需在其中一个字段中指定  primary_key=True  即可。如果 Django 发现你已经明确地设置了 Field.primary_key,它将不会添加自动 ID 列。
  • 本示例中的 CREATE TABLE SQL 使用 PostgreSQL 语法进行格式化,但值得注意的是,Django 会根据配置文件中指定的数据库后端类型来生成相应的 SQL 语句。
  • Django 支持 MySQL5.5 及更高版本。

# 三、Django 中 ORM 常用字段和参数

# 1、常用字段

字段名 作用
AutoField int 自增列,必须填入参数 primary_key=True。当 model 中如果没有自增列,则自动会创建一个列名为 id 的列。
IntegerField 一个整数类型,范围在 -2147483648 to 2147483647。
CharField 字符类型,必须提供 max_length 参数, max_length 表示字符长度。
DateField 日期字段,日期格式   YYYY-MM-DD,相当于 Python 中的 datetime.date()实例。
DateTimeField 日期时间字段,格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ],相当于 Python 中的 datetime.datetime()实例。

# 2、字段集合

AutoField(Field)
        - int自增列,必须填入参数 primary_key=True

    BigAutoField(AutoField)
        - bigint自增列,必须填入参数 primary_key=True

        注:当model中如果没有自增列,则自动会创建一个列名为id的列
        from django.db import models

        class UserInfo(models.Model):
            ## 自动创建一个列名为id的且为自增的整数列
            username = models.CharField(max_length=32)

        class Group(models.Model):
            ## 自定义自增列
            nid = models.AutoField(primary_key=True)
            name = models.CharField(max_length=32)

    SmallIntegerField(IntegerField):
        - 小整数 -32768 ~ 32767

    PositiveSmallIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
        - 正小整数 0 ~ 32767
    IntegerField(Field)
        - 整数列(有符号的) -2147483648 ~ 2147483647

    PositiveIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
        - 正整数 0 ~ 2147483647

    BigIntegerField(IntegerField):
        - 长整型(有符号的) -9223372036854775808 ~ 9223372036854775807

    BooleanField(Field)
        - 布尔值类型

    NullBooleanField(Field):
        - 可以为空的布尔值

    CharField(Field)
        - 字符类型
        - 必须提供max_length参数, max_length表示字符长度

    TextField(Field)
        - 文本类型

    EmailField(CharField):
        - 字符串类型,Django Admin以及ModelForm中提供验证机制

    IPAddressField(Field)
        - 字符串类型,Django Admin以及ModelForm中提供验证 IPV4 机制

    GenericIPAddressField(Field)
        - 字符串类型,Django Admin以及ModelForm中提供验证 Ipv4和Ipv6
        - 参数:
            protocol,用于指定Ipv4或Ipv6, 'both',"ipv4","ipv6"
            unpack_ipv4, 如果指定为True,则输入::ffff:192.0.2.1时候,可解析为192.0.2.1,开启此功能,需要protocol="both"

    URLField(CharField)
        - 字符串类型,Django Admin以及ModelForm中提供验证 URL

    SlugField(CharField)
        - 字符串类型,Django Admin以及ModelForm中提供验证支持 字母、数字、下划线、连接符(减号)

    CommaSeparatedIntegerField(CharField)
        - 字符串类型,格式必须为逗号分割的数字

    UUIDField(Field)
        - 字符串类型,Django Admin以及ModelForm中提供对UUID格式的验证

    FilePathField(Field)
        - 字符串,Django Admin以及ModelForm中提供读取文件夹下文件的功能
        - 参数:
                path,                      文件夹路径
                match=None,                正则匹配
                recursive=False,           递归下面的文件夹
                allow_files=True,          允许文件
                allow_folders=False,       允许文件夹

    FileField(Field)
        - 字符串,路径保存在数据库,文件上传到指定目录
        - 参数:
            upload_to = ""      上传文件的保存路径
            storage = None      存储组件,默认django.core.files.storage.FileSystemStorage

    ImageField(FileField)
        - 字符串,路径保存在数据库,文件上传到指定目录
        - 参数:
            upload_to = ""      上传文件的保存路径
            storage = None      存储组件,默认django.core.files.storage.FileSystemStorage
            width_field=None,   上传图片的高度保存的数据库字段名(字符串)
            height_field=None   上传图片的宽度保存的数据库字段名(字符串)

    DateTimeField(DateField)
        - 日期+时间格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ]

    DateField(DateTimeCheckMixin, Field)
        - 日期格式      YYYY-MM-DD

    TimeField(DateTimeCheckMixin, Field)
        - 时间格式      HH:MM[:ss[.uuuuuu]]

    DurationField(Field)
        - 长整数,时间间隔,数据库中按照bigint存储,ORM中获取的值为datetime.timedelta类型

    FloatField(Field)
        - 浮点型

    DecimalField(Field)
        - 10进制小数
        - 参数:
            max_digits,小数总长度
            decimal_places,小数位长度

    BinaryField(Field)
        - 二进制类型
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115

# 3、自定义字段

class UnsignedIntegerField(models.IntegerField):
    def db_type(self, connection):
        return 'integer UNSIGNED'
1
2
3

自定义 char 类型字段

class FixedCharField(models.Field):
    """
    自定义的char类型的字段类
    """
    def __init__(self, max_length, *args, **kwargs):
        super().__init__(max_length=max_length, *args, **kwargs)
        self.length = max_length

    def db_type(self, connection):
        """
        限定生成数据库表的字段类型为char,长度为length指定的值
        """
        return 'char(%s)' % self.length


class Class(models.Model):
    id = models.AutoField(primary_key=True)
    title = models.CharField(max_length=25)
    ## 使用上面自定义的char类型的字段
    cname = FixedCharField(max_length=25)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 4、ORM 字段与数据库实际字段的对应关系

'AutoField': 'integer AUTO_INCREMENT',
'BigAutoField': 'bigint AUTO_INCREMENT',
'BinaryField': 'longblob',
'BooleanField': 'bool',
'CharField': 'varchar(%(max_length)s)',
'CommaSeparatedIntegerField': 'varchar(%(max_length)s)',
'DateField': 'date',
'DateTimeField': 'datetime',
'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)',
'DurationField': 'bigint',
'FileField': 'varchar(%(max_length)s)',
'FilePathField': 'varchar(%(max_length)s)',
'FloatField': 'double precision',
'IntegerField': 'integer',
'BigIntegerField': 'bigint',
'IPAddressField': 'char(15)',
'GenericIPAddressField': 'char(39)',
'NullBooleanField': 'bool',
'OneToOneField': 'integer',
'PositiveIntegerField': 'integer UNSIGNED',
'PositiveSmallIntegerField': 'smallint UNSIGNED',
'SlugField': 'varchar(%(max_length)s)',
'SmallIntegerField': 'smallint',
'TextField': 'longtext',
'TimeField': 'time',
'UUIDField': 'char(32)',

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

# 5、字段参数

参数名 含义
null 用于表示某个字段可以为空。
unique 如果设置为 unique=True 则该字段在此表中必须是唯一的 。
db_index 如果 db_index=True 则代表着为此字段设置数据库索引。
default 为该字段设置默认值。

# 6、时间字段参数

DatetimeField、DateField、TimeField 这个三个时间字段,都可以设置如下属性。

参数名 含义
auto_now_add 配置 auto_now_add=True,创建数据记录的时候会把当前时间添加到数据库。
auto_now 配置上 auto_now=True,每次更新数据记录的时候会更新该字段。

# 7、关系字段

# 7.1、ForeignKey

外键类型在 ORM 中用来表示外键关联关系,一般把 ForeignKey 字段设置在 '一对多'中'多'的一方。

ForeignKey 可以和其他表做关联关系同时也可以和自身做关联关系。

######## 7.1.1、字段参数

参数 含义
to 设置要关联的表
to_field 设置要关联的表的字段
related_name 反向操作时,使用的字段名,用于代替原反向查询时的'表名_set'。
related_query_name 反向查询操作时,使用的连接前缀,用于替换表名。
on_delete 当删除关联表中的数据时,当前表与其关联的行的行为。
db_constraint 是否在数据库中创建外键约束,默认为 True。

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(可执行对象)

related_name 的例子:

class Classes(models.Model):
    name = models.CharField(max_length=32)

class Student(models.Model):
    name = models.CharField(max_length=32)
    theclass = models.ForeignKey(to="Classes")
1
2
3
4
5
6

当我们要查询某个班级关联的所有学生(反向查询)时,我们会这么写:

models.Classes.objects.first().student_set.all()
1

当我们在 ForeignKey 字段中添加了参数  related_name  后:

class Student(models.Model):
    name = models.CharField(max_length=32)
    theclass = models.ForeignKey(to="Classes", related_name="students")
1
2
3

这时候我们要查询某个班级关联的所有学生(反向查询)时,我们会这么写:

models.Classes.objects.first().students.all()
1

# 7.2、OneToOneField

一对一字段。

通常一对一字段用来扩展已有字段。

例子:一对一的关联关系多用在当一张表的不同字段查询频次差距过大的情况下,将本可以存储在一张表的字段拆开放置在两张表中,然后将两张表建立一对一的关联关系。

class Author(models.Model):
    name = models.CharField(max_length=32)
    info = models.OneToOneField(to='AuthorInfo')


class AuthorInfo(models.Model):
    phone = models.CharField(max_length=11)
    email = models.EmailField()
1
2
3
4
5
6
7
8

######## 7.2.1、字段参数

参数名 含义
to 设置要关联的表。
to_field 设置要关联的字段。
on_delete 当删除关联表中的数据时,当前表与其关联的行的行为。
# 7.3、ManyToManyField

用于表示多对多的关联关系。在数据库中通过第三张表来建立关联关系。

######## 7.3.1、字段参数

参数名 含义
to 设置要关联的表
related_name 反向操作时,使用的字段名,用于代替原反向查询时的'表名_set'。
related_query_name 反向查询操作时,使用的连接前缀,用于替换表名。
symmetrical 仅用于多对多自关联时,指定内部是否创建反向操作的字段。默认为 True。
through 在使用 ManyToManyField 字段时,Django 将自动生成一张表来管理多对多的关联关系。
但我们也可以手动创建第三张表来管理多对多关系,此时就需要通过 through 来指定第三张表的表名。
through_field 设置关联的字段。
db_table 默认创建第三张表时,数据库中表的名称。

######## 7.3.2 多对多关联表的三种方式 方式一、自行创建第三张表

class Book(models.Model):
    title = models.CharField(max_length=32, verbose_name="书名")


class Author(models.Model):
    name = models.CharField(max_length=32, verbose_name="作者姓名")


## 自己创建第三张表,分别通过外键关联书和作者
class Author2Book(models.Model):
    author = models.ForeignKey(to="Author")
    book = models.ForeignKey(to="Book")

    class Meta:
        unique_together = ("author", "book")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

方式二、通过 ManyToManyField 自动创建第三张表

class Book(models.Model):
    title = models.CharField(max_length=32, verbose_name="书名")

## 通过ORM自带的ManyToManyField自动创建第三张表
class Author(models.Model):
    name = models.CharField(max_length=32, verbose_name="作者姓名")
    books = models.ManyToManyField(to="Book", related_name="authors")
1
2
3
4
5
6
7

方式三、设置 ManyToManyField 并指定自行创建第三张表

class Book(models.Model):
    title = models.CharField(max_length=32, verbose_name="书名")


## 自己创建第三张表,并通过ManyToManyField指定关联
class Author(models.Model):
    name = models.CharField(max_length=32, verbose_name="作者姓名")
    books = models.ManyToManyField(to="Book", through="Author2Book", through_fields=("author", "book"))
    ## through_fields接受一个2元组('field1','field2'):
    ## 其中field1是定义ManyToManyField的模型外键的名(author),field2是关联目标模型(book)的外键名。


class Author2Book(models.Model):
    author = models.ForeignKey(to="Author")
    book = models.ForeignKey(to="Book")

    class Meta:
        unique_together = ("author", "book")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

注意:

(1)、当我们需要在第三张关系表中存储额外的字段时,就要使用第三种方式。

(2)、但是当我们使用第三种方式创建多对多关联关系时,就无法使用 set、add、remove、clear 方法来管理多对多的关系了,需要通过第三张表的 model 来管理多对多关系。

# 7.4、元信息

ORM 对应的类里面包含另一个 Meta 类,而 Meta 类封装了一些数据库的信息。主要字段如下:

字段名 含义
db_table ORM 在数据库中的表名默认是  app_类名,可以通过db_table可以重写表名。
index_together 联合索引。
unique_together 联合唯一索引。
ordering 指定默认按什么字段排序。
只有设置了该属性,我们查询到的结果才可以被 reverse()。

作者:乔克

本文链接:https://jokerbai.com

版权声明:本博客所有文章除特别声明外,均采用 署名-非商业性-相同方式共享 4.0 国际 (CC-BY-NC-SA-4.0) 许可协议。转载请注明出处!

上次更新: 2025/07/19, 11:33:23
Django之框架
Django之操作ORM

← Django之框架 Django之操作ORM→

最近更新
01
使用 Generic Webhook Trigger 触发 Jenkins 多分支流水线自动化构建
07-19
02
使用Zadig从0到1实现持续交付平台
07-19
03
基于Jira的运维发布平台
07-19
更多文章>
Theme by Vdoing | Copyright © 2019-2025 乔克 | MIT License | 渝ICP备20002153号 |
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式