完美的项目从完美的表开始
表結構設計
- 一、權限控制表結構設計
- UserInfo
- ScoreRecord
- Attendance
- Team
- Department
- Role
- Permission
- Menu
- 二、業務表結構設計
- User
- Course
- Classes
- Student
- Project
- ProjectRecord
- PaymentRecord
表結構設計是一個項目的基石,組織好各種數據之間的邏輯關系,往往能夠使開發事半功倍。
一、權限控制表結構設計
UserInfo
任何項目都要用人使用才有價值,因此設計好用戶信息表是第一步。
Django 提供了一個 AbstractUser 類,可以在這個類的基礎之上定制我們需要的 model。
我們來看一下這個類的部分源碼:
username :用戶名
username = models.CharField(_('username'),max_length=150,unique=True,help_text=_('Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.'),validators=[username_validator],error_messages={'unique': _("A user with that username already exists."),}, )first_name:名、last_name :姓
first_name = models.CharField(_('first name'), max_length=30, blank=True) last_name = models.CharField(_('last name'), max_length=150, blank=True)email :郵箱
email = models.EmailField(_('email address'), blank=True)is_staff :是否為員工
is_staff = models.BooleanField(_('staff status'),default=False,help_text=_('Designates whether the user can log into this admin site.'), )is_active :是否處于活動狀態
is_active = models.BooleanField(_('active'),default=True,help_text=_('Designates whether this user should be treated as active. ''Unselect this instead of deleting accounts.'), )date_joined :加入日期
date_joined = models.DateTimeField(_('date joined'), default=timezone.now)除了 AbstractUser 幫我們定義好的這些屬性之外,我們還要自定義一些屬性:
gender :成員性別
gender = models.IntegerField(verbose_name='性別', choices=((1, '男'), (2, '女')), default=1)avatar:成員頭像
avatar = models.ImageField(upload_to='avatars/', default='avatars/default.png')telephone :成員手機號
telephone = models.CharField(max_length=11, null=True, unique=True)roles:成員所擁有的角色
一個成員可以擁有多個角色,一個角色也可使賦予多個成員,因此 roles 字段應該是多對多的結構。
depart :成員所屬部門
一個department只能屬于一個部門,根據角色的不同可以擁有該部門負責事務內的權限,而一個部門可以擁有多名成員,因此成員與部門之間是一對多的關系。
organize :成員所屬組織
一個成員只能屬于一個組織,而一個組織可以擁有多名成員,因此成員與組織之間是一對多的關系。
最后,我們的目的想在做這個項目的同時開發出通用的、達到對象級別的權限控制組件,因此我們只借用 AbstractUser 字段而不繼承它,確定 UserInfo model 為:
# RBAC/models.py class UserInfo(models.Model):"""成員信息"""username = models.CharField(verbose_name="用戶名", max_length=150, unique=True)first_name = models.CharField(verbose_name="名", max_length=30, blank=True)last_name = models.CharField(verbose_name="姓", max_length=150, blank=True)email = models.EmailField(verbose_name="郵箱", blank=True)score = models.IntegerField(verbose_name="積分", default=10)grade = models.IntegerField(verbose_name="等級", choices=((1, "M1"), (2, "M2"), (3, "M3"), (4, "M4"), (5, "M5")),default=1)gender = models.IntegerField(verbose_name='性別', choices=((1, '男'), (2, '女')), default=1)avatar = models.ImageField(verbose_name="頭像", upload_to='avatars/', default='avatars/default.png')telephone = models.CharField(verbose_name='手機號', max_length=11, null=True, unique=True)date_joined = models.DateTimeField(verbose_name="加入日期", default=timezone.now)roles = models.ManyToManyField(verbose_name='擁有的所有角色', to="Role", blank=True)team = models.ForeignKey(verbose_name="組", to="Team", null=True, blank=True, on_delete=models.PROTECT)department = models.ForeignKey(verbose_name='部門', to="Department", null=True, blank=True, on_delete=models.PROTECT)def __str__(self):return self.usernameScoreRecord
工作室共成員分為5個等級,由個人等級積分及相關條件確定,詳情見下表:
| M1 (white) | 10 | 無 | 新成員初始積分10分 |
| M2 (blue) | 100 | 通過基礎考試 | 線上答題,隨時可嘗試 |
| M3 (yellow) | 1000 | 至少參與3個項目 | 工作室項目或自己的項目 |
| M4 (orange) | 10000 | 能夠帶隊完成項目 | 限定工作室項目 |
| M5 (red) | 100000 | 有開源框架貢獻 | 在GitHub、CSDN、博客園等社區有一定知名度 |
Attendance
class Attendance(models.Model):"""出勤記錄"""subject = models.CharField(verbose_name="主題", max_length=32)member = models.ForeignKey(verbose_name="成員", to="UserInfo", on_delete=models.PROTECT)record = models.CharField("記錄", choices=[("check", "全勤"), ("vacate", "請假"), ("late", "遲到"), ("lack", "缺勤")])score = models.IntegerField(verbose_name="處理分值")referee = models.ForeignKey(verbose_name="執行人", to="UserInfo", on_delete=models.PROTECT)def __str__(self):return "%s-%s" % (self.subject, self.member.username)Matrix工作室劃分為6個部門、4個小組,每位成員可同時擁有所屬部門和所屬分組。
Team
工作室共分四個組:1. 算法組、2. 前端組、3. 后端組、4. AI組
# RBAC/models.py class Team(models.Model):"""分組信息"""teamName = models.CharField(verbose_name="Team名稱", max_length=32, unique=True)introduce = models.TextField(verbose_name="Team介紹")# 一個組內可以擁有多名角色,但一個角色只能屬于一個組hasRoles = models.ForeignKey(verbose_name="組內擁有的角色", to="Role", null=True, blank=True, on_delete=models.PROTECT)def __str__(self):return self.teamNameDepartment
工作室下設六個部門:
1. 項目商談部
由各組組長組成,負責與甲方商談項目的需求功能與出價,整理出具體的需求分析報告或導圖。
2. 項目開發部
負責每個項目的進度監督、成員安排、整體架構設計和技術解決方案,合理調配各組成員。
3. UI設計部
與項目開發人員溝通,負責前端、移動端頁面設計,負責工作室宣傳海報、視頻的制作。
4. 學院聯系部
負責與學院相關部門建立聯系,維護工作室為學院制作的有關項目,并負責各種比賽的報名與培訓安排。
5. 成員管理部
統一管理各組成員,每月團建,同時負責新成員的培訓與學習監督,各組成員之間的流動。
6. 技術委員會
由各組組長和工作室M4、M5級別成員組成,為工作室提供技術支持和技術評審。
# RBAC/models.py class Department(models.Model):"""部門信息"""departmentName = models.CharField(verbose_name="部門名稱", max_length=32, unique=True)duty = models.TextField(verbose_name="部門職責")# 一個部門可以擁有多名角色,但一個角色只能屬于一個部門hasRoles = models.ForeignKey(verbose_name="組內擁有的角色", to="Role", null=True, blank=True, on_delete=models.PROTECT)def __str__(self):return self.departmentNameRole
通過角色將成員與權限之間關聯起來,不同的成員擁有不同的角色,不同的角色擁有不同的權限。
# RBAC/models.py class Role(models.Model):"""角色"""roleName = models.CharField(verbose_name="角色名稱", max_length=32)permissions = models.ManyToManyField(verbose_name="角色所擁有權限", to='Permission', null=True, blank=True)def __str__(self):return self.roleNamePermission
權限其實就是成員是否具有訪問某個 URL 的資格,因此權限的主要字段其實就是 URL。
# RBAC/models.py class Permission(models.Model):"""權限"""url = models.CharField(verbose_name="權限URL正則表達式", max_length=256)permissionName = models.CharField(verbose_name="權限名稱", max_length=32)alias = models.CharField(verbose_name="權限URL別名", max_length=32, unique=True)icon = models.CharField(verbose_name="權限圖標", max_length=32)menu = models.ForeignKey(verbose_name="所屬菜單", to="Menu", null=True, blank=True, on_delete=models.PROTECT,help_text="如果為 null 表示該權限不是菜單,否則為二級菜單")parentPermission = models.ForeignKey(verbose_name="父權限", to="Permission", null=True, blank=True,related_name="parentPermission", on_delete=models.PROTECT,help_text="非菜單權限需要一個二級菜單的父權限做默認展開和選中")def __str__(self):return self.permissionNameMenu
菜單用于側邊欄展示。
# RBAC/models.py class Menu(models.Model):"""菜單"""menuName = models.CharField(verbose_name="菜單名稱", max_length=32)icon = models.CharField(verbose_name="菜單圖標", max_length=32)def __str__(self):return self.menuName二、業務表結構設計
User
對于非工作室人員注冊的賬號,其實就是游客,他們也需要一個賬號,另外,工作室內部成員有時也是游客,此時,需要為游客創建一張用戶表,這時候,我們就可以直接用 AbstractUser 類做繼承了:
class User(AbstractUser):"""用戶"""avatar = models.ImageField(upload_to='avatars/', default='avatars/default.png')telephone = models.CharField(max_length=11, null=True, blank=True, unique=True)def __str__(self):return self.usernameCourse
工作室 M4、M5等級的成員可以開設課程,為方便管理,需要創建一張 Course 表。
# index/models.py class Course(models.Model):"""課程"""courseName = models.CharField(verbose_name="課程名稱", max_length=32)sketch = models.TextField(verbose_name="課程簡述")price = models.PositiveIntegerField(verbose_name="學費", help_text="游客學習收費,工作室成員學習免費")cover = models.ImageField(verbose_name="課程封面", upload_to='courseCover/', default='courseCover/default.png')grade = models.IntegerField(verbose_name="課程等級", choices=((1, "M1"), (2, "M2"), (3, "M3"), (4, "M4"), (5, "M5")))category = models.IntegerField(verbose_name="課程分類", choices=((1, "算法"), (2, "前端"), (3, "后端"), (4, "AI"), (5, "其它")))teacher = models.ForeignKey(verbose_name="開課老師", to="UserInfo", on_delete=models.PROTECT,help_text="開課老師限制為M4、M5等級成員")assistant = models.ManyToManyField(verbose_name="助教", to="UserInfo",help_text="助教限定為M3等級成員")def __str__(self):return self.courseNameClasses
每一門課程對應一個班級,用于存儲一些課程資料、學生交流和老師答疑。
# index/models.py class Classes(models.Model):"""班級"""startDate = models.DateField(verbose_name="開課日期")QQ = models.IntegerField(verbose_name="班級QQ群")graduateDate = models.DateField(verbose_name="結業日期", null=True, blank=True)explain = models.TextField(verbose_name="說明", null=True, blank=True)course = models.ForeignKey(verbose_name="課程", to="Course", on_delete=models.PROTECT)classTeacher = models.ForeignKey(verbose_name="班主任", to="UserInfo", on_delete=models.PROTECT,help_text="班主任為成員管理部成員,負責督促老師課程制作進度和學生學習進度")def __str__(self):return "%s-%s" % (self.course.courseName, self.QQ)Student
class Student(models.Model):"""學生表"""student = models.OneToOneField(verbose_name="學生信息", to="User", on_delete=models.PROTECT)QQ = models.CharField(verbose_name="學生QQ", max_length=32)telephone = models.IntegerField(verbose_name="學生手機號", max_length=32)classList = models.ManyToManyField(verbose_name="已報班級", to="Classes", null=True, blank=True)state = models.IntegerField(verbose_name="學生狀態", choices=[(1, "審核"), (2, "在讀"), (3, "畢業")], default=1)remark = models.TextField(verbose_name="備注")def __str__(self):return "%s-%s" % (self.student.username, self.classList.course.name)Project
工作室承接項目,需要一個項目表存儲項目記錄。
class Project(models.Model):"""項目"""name = models.CharField(verbose_name="項目名稱", max_length=32)contactName = models.CharField(verbose_name="聯系人姓名", max_length=32)contactInformation = models.CharField(verbose_name="聯系人聯系方式", max_length=64, help_text="QQ/WeChat/Phone")price = models.IntegerField(verbose_name="項目報價")introduce = models.TextField(verbose_name="項目介紹")superintendent = models.ForeignKey(verbose_name="項目負責人", to="UserInfo", null=True, blank=True, on_delete=models.PROTECT)startDate = models.DateField(verbose_name="接取日期", null=True, blank=True)completeDate = models.DateField(verbose_name="完結日期", null=True, blank=True)def __str__(self):return self.nameProjectRecord
為了保證項目能夠保質保量的按時完成,每個項目需要一名項目開發部的成員進行監督和跟進。
class ProjectRecord(models.Model):"""項目跟進記錄"""content = models.TextField(verbose_name="跟進內容")date = models.DateField(verbose_name="跟進日期", default=timezone.now)project = models.ForeignKey(verbose_name="跟進項目", to="Project", on_delete=models.PROTECT)superintendent = models.ForeignKey(verbose_name="跟進人", to="UserInfo", on_delete=models.PROTECT)def __str__(self):return "%s-%s" % (self.project.name, self.date)PaymentRecord
class PaymentRecord(models.Model):"""賬單記錄"""user = models.OneToOneField(verbose_name="付款人", to="User", on_delete=models.PROTECT)type = models.IntegerField(verbose_name="賬單類型", choices=[(1, "學費"), (2, "項目款"), (3, "其它")])price = models.IntegerField(verbose_name="金額")date = models.DateTimeField(verbose_name="賬單日期", default=timezone.now)state = models.IntegerField(verbose_name="狀態", choices=[(1, "審核中"), (2, "確認"), (3, "駁回")])confirmDate = models.DateTimeField(verbose_name="確認日期", null=True, blank=True)confirmUser = models.ForeignKey(verbose_name="審批人", to="UserInfo", null=True, blank=True, on_delete=models.PROTECT)remark = models.TextField(verbose_name="備注", null=True, blank=True)def __str__(self):return "%s-%s-%s" % (self.user.username, self.type, self.price)總結
以上是生活随笔為你收集整理的完美的项目从完美的表开始的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 网络机器人之爬虫
- 下一篇: Stark 组件:快速开发神器 —— 自