
Django联表查询
更新: 2025/2/24 字数: 0 字 时长: 0 分钟
前面学习中,我们通过ORM简单的创建了一张表,在实际的项目当中,用到的肯定不止一张表,而是多张表,有的表相互之间还有关联关系,接下来我们来设计更复杂的表结构,主要设计两张表:部门表、人员表。
设计表
表结构
部门表(department):
id:部门id编号
title:部门名称
id | title |
---|---|
1 | 销售 |
2 | 客服 |
3 | 运维 |
人员表(user):
id:id编号
name:姓名
password:密码
age:年龄
account:账户余额
create_time:创建时间
did:所在的部门id
id | name | password | age | account | create_time | did | sex |
---|---|---|---|---|---|---|---|
1 | 小明 | 123 | 12 | 10000 | 2022/11/11 | 2 | 男 |
2 | 小红 | 345 | 16 | 99999 | 2022/12/11 | 1 | 女 |
设计需求
设计表需要满足如下需求:
- 通过人员表(user)的did(所在的部门id)查询到某人在部门表(department)中id(部门id编号)对应的所属部门。
- 向人员表(user)中添加数据时,did字段的值必须限定在部门表(department)的id值当中,如果不在就不能添加。
设计思考
- 部门类型只有3个,即销售、客服、运维,为什么要单独分一张表?
答:**减少人员表(user)的占用空间。**假如人员表(user)有许多数据,每条数据都有did字段,两个汉字的占用空间肯定比1个数字的占用空间大很多,如果都写汉字肯定人员表(user)会变大许多。
- 将部门类型直接写到人员表(user)did字段中可行吗?
答:**在连接查询很频繁的状态下可行。**假如部门表(department)、人员表(user)的连接查询很频繁,因为连接查询也是一个耗时操作,可以考虑将部门类型直接写到人员表(user)did字段中,相当于牺牲空间换时间。
3.既然单独分一张部门表(department)是否可以单独分一张性别表(sex)?
答:**不建议。**单独分一张部门表(department)还有个优点就是里面的内容可能发生变化,比如新增/减少部门,而性别表(sex)无外乎就男、女,而且内容几乎不会发送变化,还增加了一次连表查询的耗时操作。
新建表
设计好表后,我们现在来新建人员表(user)、部门表(department)。
部门表
我们在 models.py
文件中,添加如下代码:
class Department(models.Model):
""" 部门表 """
# verbose_name注释为标题,max_length最大长度为32
title = models.CharField(verbose_name="标题", max_length=32)
人员表
我们在 models.py
文件中,添加如下代码:
class User(models.Model):
""" 员工表 """
name = models.CharField(verbose_name="姓名", max_length=16)
password = models.CharField(verbose_name="密码", max_length=64)
age = models.CharField(verbose_name="年龄", max_length=10)
# DecimalField即decimal准确小数类型,max_digits最大长度10,小数位数2,默认值0
account = models.DecimalField(verbose_name="账户余额", max_digits=10, decimal_places=2, default=0)
# DateTimeField即datetime类型
create_time = models.DateTimeField(verbose_name="创建时间")
'''
1.添加字段约束,ForeignKey表示外键,to表示要与哪张表关联,to_field表示要与哪个字段关联
2.django会将ForeignKey的变量名自动的加上_id,因此did在数据表中就是did_id
3.如果出现删减部门的情况,对应的部门的员工有两种处置方案:
- 级联删除:on_delete=models.CASCADE,当部门被撤销时,该部门下的员工一并删除
- 置空:on_delete=models.SET_NULL,当部门被撤销时,该部门下的员工部门id为空;额外添加null=True, blank=True允许当前列为空
'''
did = models.ForeignKey(to="Department", to_field="id", null=True, blank=True, on_delete=models.SET_NULL)
'''
SmallIntegerField小整数tinyint类型
choices=gender_choices是Django进行约束
'''
gender_choices = (
(0, "女"),
(1, "男")
)
sex = models.SmallIntegerField(verbose_name="性别", choices=gender_choices)
生成表
编辑完 models.py
文件后,接下来在命令行执行前面生成表的两条命令:
python manage.py makemigrations
python manage.py migrate
查看mysite数据库中,可以看到新增模型的两张表已经生成了:
查看 app01_department
表结构如下:
查看 app01_user
表结构如下:可以看到 User
模型中的 did
变量后面加上了 _id
变成了 did_id
字段。
而且还可以看到 did_id
字段外键 app01_department
表中的 id
字段:
加数据
执行下面的sql语句,向表中添加数据:
INSERT INTO app01_user values(1, '小明', '123', '12', 10000, '2022-11-11', 1, 1);
INSERT INTO app01_user values(2, '小红', '345', '16', 99999, '2022-12-11', 0, 2);
INSERT INTO app01_department values(1, '销售');
INSERT INTO app01_department values(2, '客服');
INSERT INTO app01_department values(3, '运维');
获取数据
注册视图
在 urls.py
文件中注册如下视图函数:
path('table/data/', app01.views.table_data)
视图函数
现在在 views.py
文件中添加如下代码来获取数据库中表的数据:
def table_data(request):
# 获取人员表中数据第一条数据
one_data = User.objects.first()
print(f'人员id:{one_data.id}')
print(f'人员姓名:{one_data.name}')
print(f'人员密码:{one_data.password}')
print(f'人员年龄:{one_data.age}')
print(f'人员余额:{one_data.account}')
# one_data.create_time拿到的是一个datetime类型,
# one_data.create_time需要通过strftime转成字符串
print(f'人员创建:{one_data.create_time.strftime("%Y-%m-%d")}')
# one_data.sex拿原始的数据(0,1)
# one_data.get_sex_display则是获取原始数据去gender中找到对应内容
# 格式:get_字段_display()来显示对应内容
print(f'人员性别:{one_data.get_sex_display()}')
# one_data.did_id是直接拿的数据表中的数据
# one_data.did由于在model中did外键关联了Department表,因此会直接拿到该对象
print(f'人员部门:{one_data.did.title}')
return HttpResponse("获取数据成功")
访问地址 http://127.0.0.1:8000/table/data/
后,控制台输出如下内容: