前言

  django通过继承models类来完成数据库表的创建,其中牵涉了很多数据类型和相关的知识点,这里把最近碰到的记录一下。

Django中数据类型的处理

  首先来看一下最近一个练手项目(用户管理系统)中基础的部门表用户表的定义。

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
from django.db import models


# 员工管理系统
class Department(models.Model):
"""这是部门的表:id, title"""
title = models.CharField(verbose_name='标题', max_length=32)


class UserInfo(models.Model):
"""员工表"""
name = models.CharField(verbose_name='姓名', max_length=16)
password = models.CharField(verbose_name='密码', max_length=64)
age = models.IntegerField(verbose_name='年龄')
account = models.DecimalField(verbose_name='账户余额', max_digits=10,
decimal_places=2, default=0)
create_time = models.DateTimeField(verbose_name='入职时间')

depart = models.ForeignKey(to="Department", to_field="id", on_delete=models.CASCADE)

# 性别选项
gender_choices = (
(1, "男"),
(2, "女"),
)
gender = models.SmallIntegerField(verbose_name="性别", choices=gender_choices)

  针对上面出现的类型,这里做一些相应地解释。

CharField

  CharField是基础的字符串类型,上述案例中,verbose_name=参数在许多函数中都出现了,实际上,这个参数主要是便于开发者自己了解每一个字段代表什么含义,由于我们是Django开发,因此我们使用注释的方案也可以,具体看个人喜好。对于CharField来说,max_length=是必要的,因为在创建MySQL表时,我们需要指定每一个varchar的字节数。

DecimalField

  是Python中十进制浮点数的实例。上述例子中含有两个参数,max_digits=表示数字位数,这是同时包含整数部分和小数部分的位数decimal_places=表示小数位数。default=用于在使用UserInfo.objects.create()时没有指定account参数值的时候的默认值。

DateTimeField

  DateTimeField是专门存储时间的字段类型,格式为Y-m-d H:m:s。当我们要输出这个值时,我们通常要先对其进行格式化。我们使用strftime({format})来达到这个目的。format的格式包含以下多种选择。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
%y 两位数的年份表示(00-99)
%Y 四位数的年份表示(000-9999)
%m 月份(01-12)
%d 月内中的一天(0-31)
%H 24小时制小时数(0-23)
%I 12小时制小时数(01-12)
%M 分钟数(00=59)
%S 秒(00-59)
%a 本地简化星期名称
%A 本地完整星期名称
%b 本地简化的月份名称
%B 本地完整的月份名称
%c 本地相应的日期表示和时间表示
%j 年内的一天(001-366)
%p 本地A.M.或P.M.的等价符
%U 一年中的星期数(00-53)星期天为星期的开始
%w 星期(0-6),星期天为星期的开始
%W 一年中的星期数(00-53)星期一为星期的开始
%x 本地相应的日期表示
%X 本地相应的时间表示
%Z 当前时区的名称
%% %号本身

当然,我们最常用的还是
1
2
time.strftime("%Y-%m-%d %H:%m:%s")  # 精确到秒的时间记录
time.strftime("%Y-%m-%d") # 精确到日期的时间记录

  在Django模板语法中,一般是不允许出现括号的。在前端页面,我们需要改写成

1
<span>{{ time|date:"Y-m-d" }}</span>

在Pycharm中按住Ctrl查看上述案例中date的源码,可以发现其也是一个函数,只不过使用了特殊的|符号表示而已。

ForeignKey

  ForeignKey表示的是外键,也就是将表与表之间建立联系的一种方式。在上述案例中,由于我们需要知晓员工的所属部门,因此我们使用外键将depart字段与Department中的id字段相关联。在Django自动生成表的时候,depart字段会被命名成depart_id。使用ForeignKey的时候,我们需要指定参数to=to_field=,前者指定与哪张表关联,后者指定关联的字段名。当然了,由于关联的原因,我们还需要指定on_delete=,这个参数指定当Department表中的数据删除时,UserInfo中对应这些数据的记录将要如何操作。models.CASCADE表示级联删除,即删除所有与被删除数据相关联的记录;还可以选择models.SET_NULL,这样所有关联数据的该字段将会被置空。但这有一个前提,你需要在参数列表指定该字段可以为空,即

1
department = models.ForeignKey(to="Department", to_field="id", null=True, blank=True, on_delete=models.SET_NULL)

  在读取数据中,我们需要先获取UserInfo的记录,再通过外链访问Department,即

1
2
3
4
5
6
obj = models.UserInfo.objects.fileter({筛选条件}).first()  # 获取满足筛选条件的第一个对象
print(obj.depart_id) # 访问obj.depart_id,我们得到的是部门id
title = models.Department.objects.filter(id=obj.depart_id).first().title # 再次筛选,取出title字段才是我们要的部门名称

title = models.Department.objects.filter(id=models.UserInfo.objects.filter({筛选条件}).first().depart_id).first().title
# 合并上述语句我们得到非常之长的一句数据库查询语句

显然,这句语句太长了,Django提供了另一种通过外键查询另一张表的方式,在上述例子中
1
2
obj = models.UserInfo.objects.fileter({筛选条件}).first()  # 获取满足筛选条件的第一个对象
print(obj.depart.title) # 这时直接输出了部门名字

在这种书写方式下,obj.depart直接返回根据depart_id查询到的第一个object。由于我们这个案例中ID值唯一,于是直接访问其.title即可。

  于是在前端页面,我们可以通过如下的模板语法访问每一个人对应的部门的名称:

1
2
3
4
5
6
7
8
<tbody>
{% for obj in userinfo_list %}
<tr>
<td>{{ obj.name }}</td>
<td>{{ obj.depart.title }}</td>
</tr>
{% endfor %}
</tbody>

SmallIntegerField

  该数据类型常应用于固定的枚举型,例如上例中的性别。在绝大多数情况下,性别是不会继续添加的,因此我们可以用元组的嵌套来指定这种对应关系:

1
2
3
4
gender_choices=(
(1, "男"),
(2, "女")
)

相比于存储汉字,在数据库中存储短整型占用更少的存储空间。这种情况下,你需要为SmallIntegerField指定参数choices=。这个参数接受一个嵌套元组用来指定对应关系。

  当然,这会带来一个问题,我们访问obj.gender时,会输出整型而非我们想要的汉字“男”或“女”,同样的,Django提供了一个函数:

1
2
3
4
obj.get_gender_display()  # 这个函数名称会随着你对字段名命名的不同而变化

# 命名规则
obj.get_{字段名称}_display()

  在前端页面,你可以使用模板语法来完成这个功能:

1
{{ obj.get_gender_display }}

需要注意的是:你依然不需要在函数末尾添加括号。

Django的html模板

这部分不是本文的重点,但也是Django开发中十分重要的一部分,其可以大大增加代码复用率。因此也一并写在这里。

  很多时候,许多HTML文件都具备一部分的相同结构,例如,所有页面都有页面顶部的导航栏(navigation bar),都需要引入相同的css和js等文件。Django提供模板页面来解决这个问题。我们只需要在模板文件中需要被插入的结构加入:

1
2
3
4
5
6
7
8
9
<!DOCTYPE html>
<html>
<!--省略以上html内容-->

{% block {板块名称} %}
{% endblock %}

<!--省略以下html内容-->
</html>

然后再需要使用的页面引入该模板即可,如果模板名称为layout.html,那么就可以写成这样:
1
2
3
4
5
6
{% extends 'layout.html' %}
{% block {模块名称} %}

<!--这里是你的html-->

{% endblock %}

渲染该页面时,Django会自动将其与模板layout.html拼接。一个模板中可以有多个这样的结构,一个HTML文件中也可以由多个这样的结构组成。

后记

  这篇文章字不多,但干货占比也挺高的。赶紧写出来也是方便我后续复习和查询使用。所以就浅浅地日更了一下。那这篇文章就到此结束吧!该休息咯。