42.深入模型.md 23.9 KB
Newer Older
J
jackfrued 已提交
1
## 深入模型
2

J
jackfrued 已提交
3 4 5 6 7 8 9 10 11
在上一个章节中,我们提到了Django是基于MVC架构的Web框架,MVC架构追求的是“模型”和“视图”的解耦合。所谓“模型”说得更直白一些就是数据(的表示),所以通常也被称作“数据模型”。在实际的项目中,数据模型通常通过数据库实现持久化操作,而关系型数据库在过去和当下都是持久化的首选方案,下面我们通过完成一个投票项目来讲解和模型相关的知识点。投票项目的首页会展示某在线教育平台所有的学科;点击学科可以查看到该学科的老师及其信息;用户登录后在查看老师的页面为老师投票,可以投赞成票和反对票;未登录的用户可以通过登录页进行登录;尚未注册的用户可以通过注册页输入个人信息进行注册。在这个项目中,我们使用MySQL数据库来实现数据持久化操作。

### 创建项目和应用

我们首先创建Django项目`vote`并为其添加虚拟环境和依赖项。接下来,在项目下创建名为`polls`的应用和保存模板页的文件夹`tempaltes`,项目文件夹的结构如下所示。

![](res/pycharm-vote-project.png)

根据上面描述的项目需求,我们准备了四个静态页面,分别是展示学科的页面`subjects.html`,显示学科老师的页面`teachers.html`,登录页面`login.html`,注册页面`register.html`,稍后我们会将静态页修改为Django项目所需的模板页。
12 13 14

### 配置关系型数据库MySQL 

J
jackfrued 已提交
15
1. 在MySQL中创建数据库,创建用户,授权用户访问该数据库。
16

J
jackfrued 已提交
17 18 19 20 21 22
   ```SQL
   create database vote default charset utf8;
   create user 'hellokitty'@'%' identified by 'Hellokitty.618';
   grant all privileges on vote.* to 'hellokitty'@'%';
   flush privileges;
   ```
23

J
jackfrued 已提交
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
2. 在MySQL中创建保存学科和老师信息的二维表(保存用户信息的表稍后处理)。

   ```SQL
   use vote;
   
   -- 创建学科表
   create table `tb_subject`
   (
   	`no` integer auto_increment comment '学科编号',
       `name` varchar(50) not null comment '学科名称',
       `intro` varchar(1000) not null default '' comment '学科介绍',
       `is_hot` boolean not null default 0 comment '是不是热门学科',
       primary key (`no`)
   );
   -- 创建老师表
   create table `tb_teacher`
   (
       `no` integer auto_increment comment '老师编号',
       `name` varchar(20) not null comment '老师姓名',
       `sex` boolean not null default 1 comment '老师性别',
       `birth` date not null comment '出生日期',
       `intro` varchar(1000) not null default '' comment '老师介绍',
       `photo` varchar(255) not null default '' comment '老师照片',
       `gcount` integer not null default 0 comment '好评数',
       `bcount` integer not null default 0 comment '差评数',
       `sno` integer not null comment '所属学科',
       primary key (`no`),
       foreign key (`sno`) references `tb_subject` (`no`)
   );
   ```

3. 在虚拟环境中安装连接MySQL数据库所需的依赖项。

   ```Bash
   pip install mysqlclient
59 60
   ```

J
jackfrued 已提交
61 62 63 64 65 66 67 68 69 70 71 72
   > **说明**:如果因为某些原因无法安装`mysqlclient`三方库,可以使用它的替代品`pymysql`,`pymysql`是用纯Python开发的连接MySQL的Python库,安装更容易成功,但是需要在Django项目文件夹的`__init__.py`中添加如下所示的代码。
   >
   > ```Python
   > import pymysql
   > 
   > pymysql.install_as_MySQLdb()
   > ```
   >
   > 如果使用Django 2.2及以上版本,还会遇到PyMySQL跟Django框架的兼容性问题,兼容性问题会导致项目无法运行,需要按照GitHub上PyMySQL仓库[Issues](https://github.com/PyMySQL/PyMySQL/issues/790)中提供的方法进行处理。总体来说,使用`pymysql`会比较麻烦,强烈建议大家首选安装`mysqlclient`。

4. 修改项目的settings.py文件,首先将我们创建的应用`polls`添加已安装的项目(`INSTALLED_APPS`)中,然后配置MySQL作为持久化方案。

73 74 75 76 77 78 79 80
   ```Python
   INSTALLED_APPS = [
       'django.contrib.admin',
       'django.contrib.auth',
       'django.contrib.contenttypes',
       'django.contrib.sessions',
       'django.contrib.messages',
       'django.contrib.staticfiles',
J
jackfrued 已提交
81
       'polls',
82 83 84 85
   ]
   
   DATABASES = {
       'default': {
J
jackfrued 已提交
86
           # 数据库引擎配置
87
           'ENGINE': 'django.db.backends.mysql',
J
jackfrued 已提交
88 89 90 91 92
           # 数据库的名字
           'NAME': 'vote',
           # 数据库服务器的IP地址(本机可以写localhost或127.0.0.1)
           'HOST': 'localhost',
           # 启动MySQL服务的端口号
93
           'PORT': 3306,
J
jackfrued 已提交
94 95 96 97 98 99 100
           # 数据库用户名和口令
           'USER': 'hellokitty',
           'PASSWORD': 'Hellokitty.618',
           # 数据库使用的字符集
           'CHARSET': 'utf8',
           # 数据库时间日期的时区设定
           'TIME_ZONE': 'Asia/Chongqing',
101 102 103 104 105 106
       }
   }
   ```

   在配置ENGINE属性时,常用的可选值包括:

107 108
   - `'django.db.backends.sqlite3'`:SQLite嵌入式数据库。
   - `'django.db.backends.postgresql'`:BSD许可证下发行的开源关系型数据库产品。
J
jackfrued 已提交
109 110
   - `'django.db.backends.mysql'`:甲骨文公司经济高效的数据库产品。
   - `'django.db.backends.oracle'`:甲骨文公司关系型数据库旗舰产品。
111 112 113

   其他的配置可以参考官方文档中[数据库配置](https://docs.djangoproject.com/zh-hans/2.0/ref/databases/#third-party-notes)的部分。

J
jackfrued 已提交
114
5. Django框架提供了ORM来解决数据持久化问题,ORM翻译成中文叫“对象关系映射”。因为Python是面向对象的编程语言,我们在Python程序中使用对象模型来保存数据,而关系型数据库使用关系模型,用二维表来保存数据,这两种模型并不匹配。使用ORM是为了实现对象模型到关系模型的**双向转换**,这样就不用在Python代码中书写SQL语句和游标操作,因为这些都会由ORM自动完成。利用Django的ORM,我们可以直接将刚才创建的学科表和老师表变成Django中的模型类。
115

J
jackfrued 已提交
116 117
   ```Bash
   python manage.py inspectdb > polls/models.py
118 119
   ```

J
jackfrued 已提交
120
   我们可以对自动生成的模型类稍作调整,代码如下所示。
121 122 123 124 125

   ```Python
   from django.db import models
   
   
J
jackfrued 已提交
126 127 128 129 130
   class Subject(models.Model):
       no = models.AutoField(primary_key=True, verbose_name='编号')
       name = models.CharField(max_length=50, verbose_name='名称')
       intro = models.CharField(max_length=1000, verbose_name='介绍')
       is_hot = models.BooleanField(verbose_name='是否热门')
131 132
   
       class Meta:
J
jackfrued 已提交
133 134 135 136
           managed = False
           db_table = 'tb_subject'
           verbose_name = '学科'
           verbose_name_plural = '学科'
137 138
   
   
J
jackfrued 已提交
139 140 141 142 143 144 145 146 147 148
   class Teacher(models.Model):
       no = models.AutoField(primary_key=True, verbose_name='编号')
       name = models.CharField(max_length=20, verbose_name='姓名')
       sex = models.BooleanField(default=True, verbose_name='性别')
       birth = models.DateField(verbose_name='出生日期')
       intro = models.CharField(max_length=1000, verbose_name='个人介绍')
       photo = models.ImageField(max_length=255, verbose_name='照片')
       good_count = models.IntegerField(default=0, db_column='gcount', verbose_name='好评数')
       bad_count = models.IntegerField(default=0, db_column='bcount', verbose_name='差评数')
       subject = models.ForeignKey(Subject, models.DO_NOTHING, db_column='sno')
149 150
   
       class Meta:
J
jackfrued 已提交
151 152
           managed = False
           db_table = 'tb_teacher'
153 154
   ```

J
jackfrued 已提交
155
   > **说明**:模型类都直接或间接继承自`Model`类,模型类跟关系型数据库的二维表对应,模型对象跟表中的记录对应,模型对象的属性跟表中的字段对应。如果对上面模型类的属性定义不是特别理解,可以看看本文后面提供的“模型定义参考”部分的内容。
156

J
jackfrued 已提交
157
### 使用ORM完成模型的CRUD操作
158

J
jackfrued 已提交
159
有了Django框架的ORM,我们可以直接使用面向对象的方式来实现对数据的CRUD(增删改查)操作。我们可以在PyCharm的终端中输入下面的命令进入到Django项目的交互式环境,然后尝试对模型的操作。
160

J
jackfrued 已提交
161 162 163
```Bash
python manage.py shell
```
164

J
jackfrued 已提交
165
#### 新增
166

J
jackfrued 已提交
167 168
```Python
from polls.models import Subject
169

J
jackfrued 已提交
170 171 172 173 174 175
subject1 = Subject(name='Python全栈开发', intro='当下最热门的学科', is_hot=True)
subject1.save()
subject2 = Subject(name='全栈软件测试', intro='学习自动化测试的学科', is_hot=False)
subject2.save()
subject3 = Subject(name='JavaEE分布式开发', intro='基于Java语言的服务器应用开发', is_hot=True)
```
骆昊的技术专栏's avatar
骆昊的技术专栏 已提交
176

J
jackfrued 已提交
177
#### 删除
骆昊的技术专栏's avatar
骆昊的技术专栏 已提交
178

J
jackfrued 已提交
179 180 181 182
```Python
subject = Subject.objects.get(no=2)
subject.delete()
```
骆昊的技术专栏's avatar
骆昊的技术专栏 已提交
183

J
jackfrued 已提交
184
#### 更新
骆昊的技术专栏's avatar
骆昊的技术专栏 已提交
185

J
jackfrued 已提交
186 187 188 189 190
```Shell
subject = Subject.objects.get(no=1)
subject.name = 'Python全栈+人工智能'
subject.save()
```
骆昊的技术专栏's avatar
骆昊的技术专栏 已提交
191

J
jackfrued 已提交
192
#### 查询
骆昊的技术专栏's avatar
骆昊的技术专栏 已提交
193

J
jackfrued 已提交
194
1. 查询所有对象。
骆昊的技术专栏's avatar
骆昊的技术专栏 已提交
195

J
jackfrued 已提交
196 197 198
```Shell
Subjects.objects.all()
```
骆昊的技术专栏's avatar
骆昊的技术专栏 已提交
199

J
jackfrued 已提交
200
2. 过滤数据。
骆昊的技术专栏's avatar
骆昊的技术专栏 已提交
201

J
jackfrued 已提交
202 203 204
```Shell
# 查询名称为“Python全栈+人工智能”的学科
Subject.objects.filter(name='Python全栈+人工智能')
骆昊的技术专栏's avatar
骆昊的技术专栏 已提交
205

J
jackfrued 已提交
206 207
# 查询名称包含“全栈”的学科(模糊查询)
Subject.objects.filter(name__contains='全栈')
骆昊的技术专栏's avatar
骆昊的技术专栏 已提交
208

J
jackfrued 已提交
209 210
# 查询所有热门学科
Subject.objects.filter(is_hot=True)
骆昊的技术专栏's avatar
骆昊的技术专栏 已提交
211

J
jackfrued 已提交
212 213 214
# 查询编号大于3小于10的学科
Subject.objects.filter(no__gt=3).filter(no__lt=10)
Subject.objects.filter(no__gt=3, no__lt=10)
骆昊的技术专栏's avatar
骆昊的技术专栏 已提交
215

J
jackfrued 已提交
216 217 218 219
# 查询编号在3到7之间的学科
Subject.objects.filter(no__ge=3, no__le=7)
Subject.objects.filter(no__range=(3, 7))
```
骆昊的技术专栏's avatar
骆昊的技术专栏 已提交
220

J
jackfrued 已提交
221
3. 查询单个对象。
骆昊的技术专栏's avatar
骆昊的技术专栏 已提交
222

J
jackfrued 已提交
223 224 225 226 227 228 229
```Shell
# 查询主键为1的学科
Subject.objects.get(pk=1)
Subject.objects.get(no=1)
Subject.objects.filter(no=1).first()
Subject.objects.filter(no=1).last()
```
骆昊的技术专栏's avatar
骆昊的技术专栏 已提交
230

J
jackfrued 已提交
231
4. 排序。
骆昊的技术专栏's avatar
骆昊的技术专栏 已提交
232

J
jackfrued 已提交
233 234 235 236 237 238
```Shell
# 查询所有学科按编号升序排列
Subject.objects.order_by('no')
# 查询所有部门按部门编号降序排列
Subject.objects.order_by('-no')
```
骆昊的技术专栏's avatar
骆昊的技术专栏 已提交
239

J
jackfrued 已提交
240
5. 切片(分页查询)。
骆昊的技术专栏's avatar
骆昊的技术专栏 已提交
241

J
jackfrued 已提交
242 243 244 245
```Shell
# 按编号从小到大查询前3个学科
Subject.objects.order_by('no')[:3]
```
骆昊的技术专栏's avatar
骆昊的技术专栏 已提交
246

J
jackfrued 已提交
247
6. 计数。
骆昊的技术专栏's avatar
骆昊的技术专栏 已提交
248

J
jackfrued 已提交
249 250 251 252
```Python
# 查询一共有多少个学科
Subject.objects.count()
```
骆昊的技术专栏's avatar
骆昊的技术专栏 已提交
253

J
jackfrued 已提交
254
7. 高级查询。
255

J
jackfrued 已提交
256 257 258 259
```Shell
# 查询编号为1的学科的老师
Teacher.objects.filter(subject__no=1)
Subject.objects.get(pk=1).teacher_set.all() 
骆昊的技术专栏's avatar
骆昊的技术专栏 已提交
260

J
jackfrued 已提交
261 262 263
# 查询学科名称有“全栈”二字的学科的老师
Teacher.objects.filter(subject__name__contains='全栈') 
```
骆昊的技术专栏's avatar
骆昊的技术专栏 已提交
264

J
jackfrued 已提交
265
> **说明1**:由于老师与学科之间存在多对一外键关联,所以能通过学科反向查询到该学科的老师(从一对多关系中“一”的一方查询“多”的一方),反向查询属性默认的名字是`类名小写_set`(如上面例子中的`teacher_set`),当然也可以在创建模型时通过`ForeingKey`的`related_name`属性指定反向查询属性的名字。如果不希望执行反向查询可以将`related_name`属性设置为`'+'`或者以`'+'`开头的字符串。
骆昊的技术专栏's avatar
骆昊的技术专栏 已提交
266

J
jackfrued 已提交
267
> **说明2**:ORM查询多个对象时会返回QuerySet对象,QuerySet使用了惰性查询,即在创建QuerySet对象的过程中不涉及任何数据库活动,等真正用到对象时(对QuerySet求值)才向数据库发送SQL语句并获取对应的结果,这一点在实际开发中需要引起注意!
骆昊的技术专栏's avatar
骆昊的技术专栏 已提交
268

J
jackfrued 已提交
269
> **说明3**:如果希望更新多条数据,不用先逐一获取模型对象再修改对象属性,可以直接使用QuerySet对象的`update()`方法一次性更新多条数据。
骆昊的技术专栏's avatar
骆昊的技术专栏 已提交
270

J
jackfrued 已提交
271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291
1. Django框架本身有自带的数据模型,我们稍后会用到这些模型,为此我们先做一次迁移操作。所谓迁移,就是根据模型自动生成关系数据库中的二维表,命令如下所示:

   ```Shell
   (venv)$ python manage.py migrate
   Operations to perform:
     Apply all migrations: admin, auth, contenttypes, sessions
   Running migrations:
     Applying contenttypes.0001_initial... OK
     Applying auth.0001_initial... OK
     Applying admin.0001_initial... OK
     Applying admin.0002_logentry_remove_auto_add... OK
     Applying contenttypes.0002_remove_content_type_name... OK
     Applying auth.0002_alter_permission_name_max_length... OK
     Applying auth.0003_alter_user_email_max_length... OK
     Applying auth.0004_alter_user_username_opts... OK
     Applying auth.0005_alter_user_last_login_null... OK
     Applying auth.0006_require_contenttypes_0002... OK
     Applying auth.0007_alter_validators_add_error_messages... OK
     Applying auth.0008_alter_user_username_max_length... OK
     Applying auth.0009_alter_user_last_name_max_length... OK
     Applying sessions.0001_initial... OK
骆昊的技术专栏's avatar
骆昊的技术专栏 已提交
292 293 294
   ```


J
jackfrued 已提交
295
### 利用Django后台管理模型
骆昊的技术专栏's avatar
骆昊的技术专栏 已提交
296

J
jackfrued 已提交
297
在创建好模型类之后,可以通过Django框架自带的后台管理应用(`admin`应用)实现对模型的管理。虽然实际应用中,这个后台可能并不能满足我们的需求,但是在学习Django框架时,我们可以利用`admin`应用来管理我们的模型,同时也通过它来了解一个项目的后台管理系统需要哪些功能。使用Django自带的`admin`应用步骤如下所示。
298

J
jackfrued 已提交
299
1.`admin`应用所需的表迁移到数据库中。`admin`应用本身也需要数据库的支持,而且在`admin`应用中已经定义好了相关的数据模型类,我们只需要通过模型迁移操作就能自动在数据库中生成所需的二维表。
骆昊的技术专栏's avatar
骆昊的技术专栏 已提交
300

J
jackfrued 已提交
301 302 303 304 305
   ```Bash
   python manage.py migrate
   ```
   
2. 创建访问`admin`应用的超级用户账号,这里需要输入用户名、邮箱和口令。
骆昊的技术专栏's avatar
骆昊的技术专栏 已提交
306

J
jackfrued 已提交
307 308 309
   ```Shell
   python manage.py createsuperuser
   ```
骆昊的技术专栏's avatar
骆昊的技术专栏 已提交
310

J
jackfrued 已提交
311
   > **说明**:输入口令时没有回显也不能退格,需要一气呵成完成输入。
骆昊的技术专栏's avatar
骆昊的技术专栏 已提交
312

J
jackfrued 已提交
313
3. 运行项目,在浏览器中访问`http://127.0.0.1:8000/admin`,输入刚才创建的超级用户账号和密码进行登录。
314

J
jackfrued 已提交
315
   ![](./res/django-admin-login.png)
316

J
jackfrued 已提交
317
   登录后进入管理员操作平台。
318

J
jackfrued 已提交
319
   ![](./res/django-admin-apps.png)
320

J
jackfrued 已提交
321
   注意,我们暂时还没能在`admin`应用中看到之前创建的模型类,为此需要在`polls`应用的`admin.py`文件中对需要管理的模型进行注册。
322

J
jackfrued 已提交
323
4. 注册模型类。
324

J
jackfrued 已提交
325 326 327 328
   ```Python
   from django.contrib import admin
   
   ```
329

J
jackfrued 已提交
330
from polls.models import Subject, Teacher
331

J
jackfrued 已提交
332 333 334 335 336 337 338
   admin.site.register(Subject)
   admin.site.register(Teacher)
   ```
   
   注册模型类后,就可以在后台管理系统中看到它们。
   
   ![](./res/django-admin-models.png)
339

J
jackfrued 已提交
340
5. 对模型进行CRUD操作。
骆昊的技术专栏's avatar
骆昊的技术专栏 已提交
341

J
jackfrued 已提交
342
   可以在管理员平台对模型进行C(新增)、R(查看)、U(更新)、D(删除)操作,如下图所示。
343

J
jackfrued 已提交
344
   - 添加学科。
345

J
jackfrued 已提交
346
   ![](./res/django-admin-create.png)
骆昊的技术专栏's avatar
骆昊的技术专栏 已提交
347

J
jackfrued 已提交
348
   - 查看所有学科。
骆昊的技术专栏's avatar
骆昊的技术专栏 已提交
349

J
jackfrued 已提交
350
   ![](./res/django-admin-read.png)
骆昊的技术专栏's avatar
骆昊的技术专栏 已提交
351

J
jackfrued 已提交
352
   - 删除和更新学科。
骆昊的技术专栏's avatar
骆昊的技术专栏 已提交
353

J
jackfrued 已提交
354
   ![](./res/django-admin-delete-update.png)
骆昊的技术专栏's avatar
骆昊的技术专栏 已提交
355

J
jackfrued 已提交
356
6. 注册模型管理类。
骆昊的技术专栏's avatar
骆昊的技术专栏 已提交
357

J
jackfrued 已提交
358
   可能大家已经注意到了,刚才在后台查看部门信息的时候,显示的部门信息并不直观,为此我们再修改`admin.py`文件,通过注册模型管理类,可以在后台管理系统中更好的管理模型。
骆昊的技术专栏's avatar
骆昊的技术专栏 已提交
359

J
jackfrued 已提交
360 361 362 363 364
   ```Python
   
   ```

   ![](./res/django-admin-models-detail.png)
365

J
jackfrued 已提交
366 367 368 369 370 371 372
   为了更好的查看模型数据,可以为`Subject`和`Teacher`两个模型类添加`__str__`魔法方法。修改代码后的效果如下图所示。

   ![](./res/django-amdin-models-detail-modified.png)

### 补充内容

#### Django模型最佳实践
373

374
1. 正确的为模型和关系字段命名。
骆昊的技术专栏's avatar
骆昊的技术专栏 已提交
375 376 377
2. 设置适当的`related_name`属性。
3. 用`OneToOneField`代替`ForeignKeyField(unique=True)`。
4. 通过“迁移操作”(migrate)来添加模型。
378
5. 用NoSQL来应对需要降低范式级别的场景。
骆昊的技术专栏's avatar
骆昊的技术专栏 已提交
379
6. 如果布尔类型可以为空要使用`NullBooleanField`。
380
7. 在模型中放置业务逻辑。
骆昊的技术专栏's avatar
骆昊的技术专栏 已提交
381
8. 用`<ModelName>.DoesNotExists`取代`ObjectDoesNotExists`。
382
9. 在数据库中不要出现无效数据。
骆昊的技术专栏's avatar
骆昊的技术专栏 已提交
383 384 385 386
10. 不要对`QuerySet`调用`len()`函数。
11. 将`QuerySet`的`exists()`方法的返回值用于`if`条件。
12. 用`DecimalField`来存储货币相关数据而不是`FloatField`。
13. 定义`__str__`方法。
387 388
14. 不要将数据文件放在同一个目录中。

389 390
> 说明:以上内容来自于STEELKIWI网站的[*Best Practice working with Django models in Python*](https://steelkiwi.com/blog/best-practices-working-django-models-python/),有兴趣的小伙伴可以阅读原文。

J
jackfrued 已提交
391
#### 模型定义参考
392

J
jackfrued 已提交
393
##### 字段
394 395 396 397 398 399 400 401

对字段名称的限制

- 字段名不能是Python的保留字,否则会导致语法错误
- 字段名不能有多个连续下划线,否则影响ORM查询操作

Django模型字段类

J
jackfrued 已提交
402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428
| 字段类                  | 说明                                                         |
| ----------------------- | ------------------------------------------------------------ |
| `AutoField`             | 自增ID字段                                                   |
| `BigIntegerField`       | 64位有符号整数                                               |
| `BinaryField`           | 存储二进制数据的字段,对应Python的`bytes`类型                |
| `BooleanField`          | 存储`True`或`False`                                          |
| `CharField`             | 长度较小的字符串                                             |
| `DateField`             | 存储日期,有`auto_now`和`auto_now_add`属性                   |
| `DateTimeField`         | 存储日期和日期,两个附加属性同上                             |
| `DecimalField`          | 存储固定精度小数,有`max_digits`(有效位数)和`decimal_places`(小数点后面)两个必要的参数 |
| `DurationField`         | 存储时间跨度                                                 |
| `EmailField`            | 与`CharField`相同,可以用`EmailValidator`验证                |
| `FileField`             | 文件上传字段                                                 |
| `FloatField`            | 存储浮点数                                                   |
| `ImageField`            | 其他同`FileFiled`,要验证上传的是不是有效图像                |
| `IntegerField`          | 存储32位有符号整数。                                         |
| `GenericIPAddressField` | 存储IPv4或IPv6地址                                           |
| `NullBooleanField`      | 存储`True`、`False`或`null`值                                |
| `PositiveIntegerField`  | 存储无符号整数(只能存储正数)                               |
| `SlugField`             | 存储slug(简短标注)                                         |
| `SmallIntegerField`     | 存储16位有符号整数                                           |
| `TextField`             | 存储数据量较大的文本                                         |
| `TimeField`             | 存储时间                                                     |
| `URLField`              | 存储URL的`CharField`                                         |
| `UUIDField`             | 存储全局唯一标识符                                           |

##### 字段属性
429 430 431

通用字段属性

J
jackfrued 已提交
432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499
| 选项             | 说明                                                         |
| ---------------- | ------------------------------------------------------------ |
| `null`           | 数据库中对应的字段是否允许为`NULL`,默认为`False`            |
| `blank`          | 后台模型管理验证数据时,是否允许为`NULL`,默认为`False`      |
| `choices`        | 设定字段的选项,各元组中的第一个值是设置在模型上的值,第二值是人类可读的值 |
| `db_column`      | 字段对应到数据库表中的列名,未指定时直接使用字段的名称       |
| `db_index`       | 设置为`True`时将在该字段创建索引                             |
| `db_tablespace`  | 为有索引的字段设置使用的表空间,默认为`DEFAULT_INDEX_TABLESPACE` |
| `default`        | 字段的默认值                                                 |
| `editable`       | 字段在后台模型管理或`ModelForm`中是否显示,默认为`True`      |
| `error_messages` | 设定字段抛出异常时的默认消息的字典,其中的键包括`null`、`blank`、`invalid`、`invalid_choice`、`unique`和`unique_for_date` |
| `help_text`      | 表单小组件旁边显示的额外的帮助文本。                         |
| `primary_key`    | 将字段指定为模型的主键,未指定时会自动添加`AutoField`用于主键,只读。 |
| `unique`         | 设置为`True`时,表中字段的值必须是唯一的                     |
| `verbose_name`   | 字段在后台模型管理显示的名称,未指定时使用字段的名称         |

`ForeignKey`属性

1. `limit_choices_to`:值是一个Q对象或返回一个Q对象,用于限制后台显示哪些对象。
2. `related_name`:用于获取关联对象的关联管理器对象(反向查询),如果不允许反向,该属性应该被设置为`'+'`,或者以`'+'`结尾。
3. `to_field`:指定关联的字段,默认关联对象的主键字段。
4. `db_constraint`:是否为外键创建约束,默认值为`True`。
5. `on_delete`:外键关联的对象被删除时对应的动作,可取的值包括`django.db.models`中定义的:
   - `CASCADE`:级联删除。
   - `PROTECT`:抛出`ProtectedError`异常,阻止删除引用的对象。
   - `SET_NULL`:把外键设置为`null`,当`null`属性被设置为`True`时才能这么做。
   - `SET_DEFAULT`:把外键设置为默认值,提供了默认值才能这么做。

`ManyToManyField`属性

1. `symmetrical`:是否建立对称的多对多关系。
2. `through`:指定维持多对多关系的中间表的Django模型。
3. `throughfields`:定义了中间模型时可以指定建立多对多关系的字段。
4. `db_table`:指定维持多对多关系的中间表的表名。

##### 模型元数据选项

| 选项                    | 说明                                                         |
| ----------------------- | ------------------------------------------------------------ |
| `abstract`              | 设置为True时模型是抽象父类                                   |
| `app_label`             | 如果定义模型的应用不在INSTALLED_APPS中可以用该属性指定       |
| `db_table`              | 模型使用的数据表名称                                         |
| `db_tablespace`         | 模型使用的数据表空间                                         |
| `default_related_name`  | 关联对象回指这个模型时默认使用的名称,默认为<model_name>_set |
| `get_latest_by`         | 模型中可排序字段的名称。                                     |
| `managed`               | 设置为True时,Django在迁移中创建数据表并在执行flush管理命令时把表移除 |
| `order_with_respect_to` | 标记对象为可排序的                                           |
| `ordering`              | 对象的默认排序                                               |
| `permissions`           | 创建对象时写入权限表的额外权限                               |
| `default_permissions`   | 默认为`('add', 'change', 'delete')`                          |
| `unique_together`       | 设定组合在一起时必须独一无二的字段名                         |
| `index_together`        | 设定一起建立索引的多个字段名                                 |
| `verbose_name`          | 为对象设定人类可读的名称                                     |
| `verbose_name_plural`   | 设定对象的复数名称                                           |

#### 查询参考

##### 按字段查找可以用的条件

1. `exact` / `iexact`:精确匹配/忽略大小写的精确匹配查询
2. `contains` / `icontains` / `startswith` / `istartswith` / `endswith` / `iendswith`:基于`like`的模糊查询
3. `in` :集合运算
4. `gt` / `gte` / `lt` / `lte`:大于/大于等于/小于/小于等于关系运算
5. `range`:指定范围查询(SQL中的`between…and…`)
6. `year` / `month` / `day` / `week_day` / `hour` / `minute` / `second`:查询时间日期
7. `isnull`:查询空值(True)或非空值(False)
8. `search`:基于全文索引的全文检索(一般很少使用)
9. `regex` / `iregex`:基于正则表达式的模糊匹配查询
500 501