Django 后端实战指南_10:用户扩展档案信息表

阶段 10:用户扩展档案信息表

合辑 :Django 系统阶段开发手册 | 阶段 :10 / 18 | 定位 :新增用户扩展档案表并接入迁移与后台管理 | 建议学时:4--6 小时

大家好,我是小马不起床。


阶段导语

本阶段在权限链路(用户 → 角色 → 权限)之外,开辟第二条数据主线:用户 → 用户扩展档案。通过新增 sys_user_profile 表并与 sys_user 建立外键(Foreign Key)关系,为后续档案查询与修改接口提供数据基础。

本阶段仅完成数据表与模型层的构建:定义模型、生成并执行迁移(migration)、接入 Django Admin,并在 MySQL 中校验建表结果。档案接口、Vue 页面、头像上传与权限控制均不在本阶段范围内。


学习目标

完成本阶段后,应能够:

  • 依据给定 SQL 设计用户扩展档案表,并说明其与 sys_user 的一对一关联关系
  • 在 rbac/models.py 中定义 SysUserProfile 模型,正确使用外键字段与 choices 枚举
  • 将模型注册到 Django Admin,配置列表展示、搜索与过滤项
  • 执行 makemigrations 与 migrate,并在 MySQL 中确认建表成功
  • 通过 Django Shell 与 SQL 联合查询创建并核验档案测试数据

前置知识

本阶段依赖阶段 9(阶段 9:前后端完整联调和问题修复.md)的内容:

前置条目 具体要求
RBAC 四表 理解 sys_user、sys_role、sys_role_permission、sys_permission 的关系
SysUser 模型 已存在 SysUser 模型,含 user_id、username、real_name 等字段
迁移流程 掌握 makemigrations 与 migrate 的基本用法
Django Admin 了解模型的后台注册方式

若上述内容尚不熟悉,建议先完成阶段 9 的学习。


目录

  1. 数据表设计与目标范围
  2. [定义 SysUserProfile 模型](#定义 SysUserProfile 模型)
  3. 模型字段说明
  4. [注册到 Django Admin](#注册到 Django Admin)
  5. 生成并执行迁移
  6. [校验 MySQL 表结构](#校验 MySQL 表结构)
  7. 创建与查看测试档案
  8. 可选:将档案纳入初始化命令
  9. 阶段完成标准与系统关系
  10. 阶段小结
  11. 常见问题与排查
  12. 下一阶段衔接

1. 数据表设计与目标范围

1.1 本阶段要实现与暂不实现的内容

本阶段实现 本阶段暂不实现
新增 sys_user_profile 表 档案接口
让 sys_user_profile 关联 sys_user Vue 页面
在 Django Admin 后台管理用户档案 头像上传
在 MySQL 中确认表创建成功 权限控制

1.2 建表 SQL

本阶段使用的建表语句如下:

sql 复制代码
CREATE TABLE `sys_user_profile` (
    `profile_id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '档案ID',
    `user_id` BIGINT NOT NULL COMMENT '用户ID',
    `level` INT DEFAULT NULL COMMENT '等级',
    `gender` INT DEFAULT NULL COMMENT '性别',
    `birthday` DATE DEFAULT NULL COMMENT '生日',
    `height_cm` DECIMAL(5,2) DEFAULT NULL COMMENT '身高(cm)',
    `weight_kg` DECIMAL(5,2) DEFAULT NULL COMMENT '体重(kg)',
    `avatar_url` VARCHAR(255) DEFAULT NULL COMMENT '头像地址',
    `intro` TEXT DEFAULT NULL COMMENT '简介',
    `create_time` DATETIME DEFAULT NULL COMMENT '账号创建时间',
    `join_time` DATETIME DEFAULT NULL COMMENT '入职/开卡时间',
    `expire_date` DATE DEFAULT NULL COMMENT '到期/停卡时间',
    PRIMARY KEY (`profile_id`),
    CONSTRAINT `fk_profile_user` FOREIGN KEY (`user_id`) REFERENCES `sys_user` (`user_id`)
) ENGINE=InnoDB COMMENT='用户扩展档案信息';

该表与用户表的关系为:

text 复制代码
sys_user
  ↓ user_id
sys_user_profile

即一个用户可以有一份扩展档案信息。需要说明的是,该 SQL 未对 user_id 施加唯一约束,数据库层面允许一个用户存在多条档案记录;本阶段严格沿用该 SQL 定义实现。

要点:

  • 要点:本阶段只构建数据表与模型层,接口与前端不在范围内。
  • 要点 :sys_user_profile 通过 user_id 外键关联 sys_user.user_id。
  • 要点 :建表 SQL 未对 user_id 设唯一约束,数据库允许一个用户多条档案。

2. 定义 SysUserProfile 模型

打开文件 backend/rbac/models.py,在文件末尾、SysUser 类之后追加以下模型:

python 复制代码
class SysUserProfile(models.Model):
    """
    用户扩展档案信息表
    对应 MySQL 表:sys_user_profile
    """

    GENDER_CHOICES = (
        (0, "未知"),
        (1, "男"),
        (2, "女"),
    )

    profile_id = models.BigAutoField(
        primary_key=True,
        verbose_name="档案ID"
    )

    user = models.ForeignKey(
        SysUser,
        on_delete=models.PROTECT,
        db_column="user_id",
        related_name="profiles",
        verbose_name="用户ID"
    )

    level = models.IntegerField(
        null=True,
        blank=True,
        verbose_name="等级"
    )

    gender = models.IntegerField(
        null=True,
        blank=True,
        choices=GENDER_CHOICES,
        verbose_name="性别"
    )

    birthday = models.DateField(
        null=True,
        blank=True,
        verbose_name="生日"
    )

    height_cm = models.DecimalField(
        max_digits=5,
        decimal_places=2,
        null=True,
        blank=True,
        verbose_name="身高(cm)"
    )

    weight_kg = models.DecimalField(
        max_digits=5,
        decimal_places=2,
        null=True,
        blank=True,
        verbose_name="体重(kg)"
    )

    avatar_url = models.CharField(
        max_length=255,
        null=True,
        blank=True,
        verbose_name="头像地址"
    )

    intro = models.TextField(
        null=True,
        blank=True,
        verbose_name="简介"
    )

    create_time = models.DateTimeField(
        null=True,
        blank=True,
        verbose_name="账号创建时间"
    )

    join_time = models.DateTimeField(
        null=True,
        blank=True,
        verbose_name="入职/开卡时间"
    )

    expire_date = models.DateField(
        null=True,
        blank=True,
        verbose_name="到期/停卡时间"
    )

    class Meta:
        db_table = "sys_user_profile"
        verbose_name = "用户扩展档案"
        verbose_name_plural = "用户扩展档案"

    def __str__(self):
        return f"{self.user.username} 的档案"

要点:

  • 要点 :模型追加在 SysUser 类之后,Meta.db_table 固定为 sys_user_profile,与 SQL 表名一致。
  • 要点 :user 字段以 db_column="user_id" 复用 SQL 中的列名,避免 Django 自动生成 user_id_id。
  • 要点 :__str__ 返回「用户名 + 的档案」,用于 Admin 列表显示。

3. 模型字段说明

3.1 字段一览

字段 类型 约束 说明
profile_id BigAutoField 主键、自增 档案表主键
user ForeignKey(SysUser) db_column="user_id"、on_delete=PROTECT、related_name="profiles" 当前档案所属的用户
level IntegerField null、blank 等级
gender IntegerField null、blank、choices=GENDER_CHOICES 性别,存数字
birthday DateField null、blank 生日
height_cm DecimalField(5,2) null、blank 身高(cm)
weight_kg DecimalField(5,2) null、blank 体重(kg)
avatar_url CharField(255) null、blank 头像地址
intro TextField null、blank 简介
create_time DateTimeField null、blank 账号创建时间
join_time DateTimeField null、blank 入职/开卡时间
expire_date DateField null、blank 到期/停卡时间

3.2 关键字段解释

profile_id 对应 SQL 的 profile_id BIGINT NOT NULL AUTO_INCREMENT,Django 写法为 models.BigAutoField(primary_key=True),作为档案表自增主键。

user 对应 SQL 的外键约束 CONSTRAINT fk_profile_user FOREIGN KEY (user_id) REFERENCES sys_user (user_id),Django 写法为:

python 复制代码
user = models.ForeignKey(
    SysUser,
    on_delete=models.PROTECT,
    db_column="user_id"
)

其作用为标记当前档案属于哪个用户,例如 admin 用户对应 admin 的档案、zhangsan 用户对应 zhangsan 的档案。此处使用 on_delete=models.PROTECT,含义是当用户仍有档案时不允许直接删除该用户,属于较安全的删除策略。

gender 字段通过 GENDER_CHOICES 定义枚举,数据库存储数字,Admin 后台显示中文:

存储值 显示文本
0 未知
1 男
2 女

height_cm 与 weight_kg 对应 SQL 的 DECIMAL(5,2),Django 写法为 models.DecimalField(max_digits=5, decimal_places=2),表示最多 5 位数字、其中 2 位小数,例如 180.50、65.20。

要点:

  • 要点 :on_delete=PROTECT 阻止删除仍持有档案的用户。
  • 要点 :db_column="user_id" 使外键列名与既有 SQL 保持一致。
  • 要点 :gender 存数字、经 choices 在后台映射中文。
  • 要点 :DECIMAL(5,2) 对应 max_digits=5, decimal_places=2。

4. 注册到 Django Admin

打开文件 backend/rbac/admin.py,先修改导入。原语句可能为:

python 复制代码
from .models import SysPermission, SysRole, SysRolePermission, SysUser

改为:

python 复制代码
from .models import (
    SysPermission,
    SysRole,
    SysRolePermission,
    SysUser,
    SysUserProfile,
)

在文件末尾追加注册代码:

python 复制代码
@admin.register(SysUserProfile)
class SysUserProfileAdmin(admin.ModelAdmin):
    list_display = (
        "profile_id",
        "user",
        "level",
        "gender",
        "birthday",
        "height_cm",
        "weight_kg",
        "join_time",
        "expire_date",
    )

    search_fields = (
        "user__username",
        "user__real_name",
        "intro",
    )

    list_filter = (
        "gender",
        "level",
    )

要点:

  • 要点 :导入需补入 SysUserProfile,否则注册时报错。
  • 要点 :search_fields 使用 user__username 等跨关系字段,支持按用户名与真实姓名检索。
  • 要点 :list_filter 提供性别与等级的过滤侧栏。

5. 生成并执行迁移

确认位于后端目录 rbac_project/backend,生成迁移文件:

bash 复制代码
python3 manage.py makemigrations rbac

正常输出类似:

text 复制代码
Migrations for 'rbac':
  rbac/migrations/0002_sysuserprofile.py
    + Create model SysUserProfile

随后执行迁移建表:

bash 复制代码
python3 manage.py migrate

正常输出类似:

text 复制代码
Applying rbac.0002_sysuserprofile... OK

这一步完成后,MySQL 中新增一张 sys_user_profile 表。

要点:

  • 要点 :makemigrations 生成 0002_sysuserprofile.py 迁移文件,migrate 将其落到数据库。
  • 要点:两条命令需在后端目录执行,工作目录错误会导致找不到 app。
  • 要点 :迁移成功的关键标志是输出 Applying rbac.0002_sysuserprofile... OK。

6. 校验 MySQL 表结构

进入 MySQL 并选择数据库:

bash 复制代码
mysql -u root -p
sql 复制代码
USE rbac_db;

查看全部表:

sql 复制代码
SHOW TABLES;

结果中应出现 sys_user_profile。查看表结构:

sql 复制代码
DESC sys_user_profile;

应看到如下字段:profile_id、user_id、level、gender、birthday、height_cm、weight_kg、avatar_url、intro、create_time、join_time、expire_date。校验完成后退出 MySQL:

sql 复制代码
exit;

要点:

  • 要点 :SHOW TABLES 确认表存在,DESC 确认列齐全。
  • 要点 :DESC 结果中的列名为 user_id(由 db_column 指定),而非 user_id_id。

7. 创建与查看测试档案

7.1 在 Django Shell 创建测试档案

进入 shell:

bash 复制代码
python manage.py shell

输入:

python 复制代码
from datetime import date, datetime
from rbac.models import SysUser, SysUserProfile

admin = SysUser.objects.get(username="admin")

profile = SysUserProfile.objects.create(
    user=admin,
    level=1,
    gender=1,
    birthday=date(1998, 1, 1),
    height_cm=175.50,
    weight_kg=70.25,
    avatar_url="https://example.com/avatar.png",
    intro="这是管理员的扩展档案",
    create_time=datetime.now(),
    join_time=datetime.now(),
    expire_date=date(2030, 12, 31),
)

profile

若返回类似 <SysUserProfile: admin 的档案>,说明创建成功。退出 shell:

python 复制代码
exit()

7.2 在 MySQL 查看档案数据

进入 MySQL 并选择数据库:

bash 复制代码
mysql -u root -p
sql 复制代码
USE rbac_db;

执行联合查询:

sql 复制代码
SELECT
    p.profile_id,
    u.username,
    u.real_name,
    p.level,
    p.gender,
    p.birthday,
    p.height_cm,
    p.weight_kg,
    p.avatar_url,
    p.intro,
    p.create_time,
    p.join_time,
    p.expire_date
FROM sys_user_profile p
JOIN sys_user u ON p.user_id = u.user_id;

结果中可看到刚创建的 admin 档案。

要点:

  • 要点 :objects.create(user=admin, ...) 直接传入 SysUser 实例建立关联。
  • 要点 :Shell 返回 <SysUserProfile: admin 的档案> 即代表写入成功。
  • 要点 :联合查询通过 JOIN sys_user 展示档案所属用户名与真实姓名。

8. 可选:将档案纳入初始化命令

若希望执行初始化命令时自动为 admin 与 zhangsan 创建档案:

bash 复制代码
python manage.py init_rbac_data

可修改文件 backend/rbac/management/commands/init_rbac_data.py。先修改导入:

python 复制代码
from rbac.models import SysPermission, SysRole, SysUser, SysUserProfile

然后在文件末尾(即创建 admin 与 zhangsan 用户之后)追加:

python 复制代码
from datetime import date, datetime

admin_user = SysUser.objects.filter(username="admin").first()
zhangsan_user = SysUser.objects.filter(username="zhangsan").first()

if admin_user and not SysUserProfile.objects.filter(user=admin_user).exists():
    SysUserProfile.objects.create(
        user=admin_user,
        level=10,
        gender=1,
        birthday=date(1998, 1, 1),
        height_cm=175.00,
        weight_kg=70.00,
        avatar_url="",
        intro="管理员账号",
        create_time=datetime.now(),
        join_time=datetime.now(),
        expire_date=date(2030, 12, 31),
    )

    self.stdout.write(
        self.style.SUCCESS("创建 admin 用户档案")
    )

if zhangsan_user and not SysUserProfile.objects.filter(user=zhangsan_user).exists():
    SysUserProfile.objects.create(
        user=zhangsan_user,
        level=1,
        gender=1,
        birthday=date(2000, 5, 1),
        height_cm=172.00,
        weight_kg=65.00,
        avatar_url="",
        intro="普通用户账号",
        create_time=datetime.now(),
        join_time=datetime.now(),
        expire_date=date(2030, 12, 31),
    )

    self.stdout.write(
        self.style.SUCCESS("创建 zhangsan 用户档案")
    )

追加后重新执行:

bash 复制代码
python manage.py init_rbac_data

要点:

  • 要点 :以 filter(user=...).exists() 做幂等判断,避免重复初始化时产生多条档案。
  • 要点 :档案创建代码需放在用户创建之后,确保 admin、zhangsan 已存在。
  • 要点:本步骤为可选项,不影响阶段主流程。

9. 阶段完成标准与系统关系

9.1 完成标准

需逐项确认:

  1. models.py 中新增 SysUserProfile 模型
  2. admin.py 中注册 SysUserProfile
  3. makemigrations 成功
  4. migrate 成功
  5. MySQL 中出现 sys_user_profile 表
  6. Django Admin 中能看到「用户扩展档案」
  7. 可以给 admin 或 zhangsan 创建档案数据

9.2 当前系统关系

权限主线保持不变:

text 复制代码
sys_user
  ↓ role_id
sys_role
  ↓
sys_role_permission
  ↓
sys_permission

本阶段新增档案主线:

text 复制代码
sys_user
  ↓ user_id
sys_user_profile

系统内由此形成两条主线:

主线 链路
权限主线 用户 → 角色 → 权限
档案主线 用户 → 用户扩展档案

要点:

  • 要点:完成标准覆盖模型、注册、迁移、建表、后台与测试数据六类校验。
  • 要点 :权限主线与档案主线均以 sys_user 为起点,互不干扰。

阶段小结

环节 核心操作 结果
表设计 依据给定 SQL 定义 sys_user_profile 与 sys_user 建立 user_id 外键关系
模型定义 在 rbac/models.py 追加 SysUserProfile db_table 与 SQL 表名一致
字段映射 外键、choices、DecimalField 等 数字存库、后台显示中文
Admin 注册 @admin.register 配置展示/搜索/过滤 后台可管理用户档案
迁移 makemigrations + migrate MySQL 新增 sys_user_profile
建表校验 SHOW TABLES / DESC 确认表与列存在
测试数据 Shell create + SQL 联合查询 生成并核验 admin 档案
初始化集成(可选) 修改 init_rbac_data 命令 初始化时自动生成档案

常见问题与排查

现象 原因 处理
迁移报找不到模型 SysUserProfile 未写入 rbac/models.py 或写错缩进 确认模型类位于 models.py 且继承 models.Model
Admin 页面无「用户扩展档案」 admin.py 未导入或未注册 SysUserProfile 补充导入并添加 @admin.register(SysUserProfile)
MySQL 无 sys_user_profile 表 只执行了 makemigrations,未执行 migrate 在后端目录执行 python3 manage.py migrate
外键列名与 SQL 不符 未设置 db_column="user_id" 在 user 字段显式指定 db_column
创建档案报用户不存在 SysUser.objects.get(username="admin") 未匹配到用户 先确认 admin 用户已创建,或改用初始化命令生成
删除用户被拒绝 on_delete=PROTECT 阻止删除持有档案的用户 先删除或转移该用户的档案记录后再删除用户

下一阶段衔接

阶段 11(阶段 11:用户档案查询和修改接口.md)将基于本阶段建成的 sys_user_profile 表,实现档案的查询与修改接口:

text 复制代码
GET  /api/profile/me/     查看当前用户档案
PUT  /api/profile/me/     修改当前用户档案

本阶段的模型与数据是阶段 11 接口层的直接依赖,需确保建表与测试数据均已就绪。

相关推荐
Want5951 小时前
Python跳动的爱心①
开发语言·python·数学建模
SamChan901 小时前
PDF 翻译后 1,250 变成 1.250,是错了吗?用 Python 核对数字格式
python·pdf·ocr·数据校验·文档翻译
Yolanda_20221 小时前
30.利用GPU训练(一)
python
迅猛龙办公室1 小时前
Python实现PM空气质量提醒
服务器·前端·python
小马不起床1 小时前
Django 后端实战指南_9:前后端完整联调和问题修复
python·django·状态模式
pride.li2 小时前
第12章 Python 教程-流程控制:循环结构
linux·服务器·python·算法
ycydynq2 小时前
django用Bootstrap 模态框 在同一页面实现增删改查
django·bootstrap·jquery
鬼手点金2 小时前
模型即 Agent:当模型本身成为产品
开发语言·前端·人工智能·python·机器学习
田里的水稻2 小时前
PyTorch-Dataset\DataLoader数据加载
人工智能·pytorch·python