Skip to content

Django联表查询

更新: 2025/2/24 字数: 0 字 时长: 0 分钟

前面学习中,我们通过ORM简单的创建了一张表,在实际的项目当中,用到的肯定不止一张表,而是多张表,有的表相互之间还有关联关系,接下来我们来设计更复杂的表结构,主要设计两张表:部门表、人员表。

设计表

表结构

部门表(department):

id:部门id编号
title:部门名称
idtitle
1销售
2客服
3运维

人员表(user):

id:id编号
name:姓名
password:密码
age:年龄
account:账户余额
create_time:创建时间
did:所在的部门id
idnamepasswordageaccountcreate_timedidsex
1小明12312100002022/11/112
2小红34516999992022/12/111

设计需求

设计表需要满足如下需求:

  1. 通过人员表(user)的did(所在的部门id)查询到某人在部门表(department)中id(部门id编号)对应的所属部门。
  2. 向人员表(user)中添加数据时,did字段的值必须限定在部门表(department)的id值当中,如果不在就不能添加。

设计思考

  1. 部门类型只有3个,即销售、客服、运维,为什么要单独分一张表?

答:**减少人员表(user)的占用空间。**假如人员表(user)有许多数据,每条数据都有did字段,两个汉字的占用空间肯定比1个数字的占用空间大很多,如果都写汉字肯定人员表(user)会变大许多。

  1. 将部门类型直接写到人员表(user)did字段中可行吗?

答:**在连接查询很频繁的状态下可行。**假如部门表(department)、人员表(user)的连接查询很频繁,因为连接查询也是一个耗时操作,可以考虑将部门类型直接写到人员表(user)did字段中,相当于牺牲空间换时间。

3.既然单独分一张部门表(department)是否可以单独分一张性别表(sex)?

答:**不建议。**单独分一张部门表(department)还有个优点就是里面的内容可能发生变化,比如新增/减少部门,而性别表(sex)无外乎就男、女,而且内容几乎不会发送变化,还增加了一次连表查询的耗时操作。

新建表

设计好表后,我们现在来新建人员表(user)、部门表(department)。

部门表

我们在 models.py 文件中,添加如下代码:

python
class Department(models.Model):
    """ 部门表 """
    # verbose_name注释为标题,max_length最大长度为32
    title = models.CharField(verbose_name="标题", max_length=32)

QQ截图20220516215543

人员表

我们在 models.py 文件中,添加如下代码:

python
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)

QQ截图20220516215639

生成表

编辑完 models.py 文件后,接下来在命令行执行前面生成表的两条命令:

python manage.py makemigrations
python manage.py migrate

QQ截图20220516215900

查看mysite数据库中,可以看到新增模型的两张表已经生成了:

QQ截图20220516220038

查看 app01_department 表结构如下:

QQ截图20220516220145

查看 app01_user 表结构如下:可以看到 User 模型中的 did 变量后面加上了 _id 变成了 did_id 字段。

QQ截图20220516220256

而且还可以看到 did_id 字段外键 app01_department 表中的 id 字段:

QQ截图20220516220639

加数据

执行下面的sql语句,向表中添加数据:

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, '运维');

QQ截图20220529190019

获取数据

注册视图

urls.py 文件中注册如下视图函数:

python
path('table/data/', app01.views.table_data)

QQ截图20220529222119

视图函数

现在在 views.py 文件中添加如下代码来获取数据库中表的数据:

python
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/ 后,控制台输出如下内容:

QQ截图20220529221900