models.py 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. from django.db import models
  2. from django.utils.translation import gettext_lazy as _
  3. from django.utils import timezone
  4. class Users(models.Model):
  5. """核心用户模型 (继承现有结构)"""
  6. user_id = models.AutoField(primary_key=True, verbose_name="用户ID")
  7. name = models.CharField(max_length=80, verbose_name='姓名')
  8. openid = models.CharField(max_length=100, unique=True, verbose_name='OPENID')
  9. appid = models.CharField(max_length=100, verbose_name='APPID')
  10. # 权限系统
  11. vip = models.PositiveIntegerField(default=1, verbose_name='VIP等级')
  12. vip_time = models.DateTimeField(auto_now_add=True, verbose_name='VIP生效时间')
  13. # 账户状态
  14. is_delete = models.BooleanField(default=False, verbose_name='删除标记')
  15. developer = models.BooleanField(default=False, verbose_name='开发者标记')
  16. # 安全信息
  17. t_code = models.CharField(max_length=100, unique=True, verbose_name='交易验证码')
  18. ip = models.GenericIPAddressField(verbose_name='注册IP')
  19. # 基本信息
  20. avatar = models.CharField(max_length=200, default='/static/img/user.jpg', verbose_name='用户头像')
  21. create_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
  22. update_time = models.DateTimeField(auto_now=True, verbose_name='更新时间')
  23. class Meta:
  24. db_table = 'user_profile'
  25. verbose_name = '用户档案'
  26. verbose_name_plural = "用户档案"
  27. ordering = ['-create_time']
  28. def __str__(self):
  29. return f"{self.name}(ID:{self.user_id})"
  30. class AcademicProfile(models.Model):
  31. """学术信息扩展模型 (与用户一对一关联)"""
  32. class AcademicRole(models.TextChoices):
  33. UNDERGRAD = 'UG', _('本科生')
  34. MASTER = 'MS', _('硕士生')
  35. PHD = 'PhD', _('博士生')
  36. POSTDOC = 'PD', _('博士后')
  37. FACULTY = 'FAC', _('教职工')
  38. RESEARCHER = 'RES', _('研究员')
  39. user = models.OneToOneField(
  40. Users,
  41. on_delete=models.CASCADE,
  42. primary_key=True,
  43. related_name='user_academic_profile',
  44. verbose_name='关联用户'
  45. )
  46. # 学术身份
  47. role = models.CharField(
  48. max_length=10,
  49. choices=AcademicRole.choices,
  50. default=AcademicRole.MASTER,
  51. verbose_name='学术身份'
  52. )
  53. # 年级信息
  54. enrollment_year = models.PositiveIntegerField(
  55. verbose_name='入学年份',
  56. help_text='格式:YYYY(如2023)'
  57. )
  58. graduation_year = models.PositiveIntegerField(
  59. null=True,
  60. blank=True,
  61. verbose_name='预计毕业年份'
  62. )
  63. # 学术单位
  64. department = models.CharField(max_length=100, verbose_name='院系/研究所')
  65. major = models.CharField(max_length=100, verbose_name='专业方向')
  66. # 研究标签
  67. research_tags = models.CharField(
  68. max_length=255,
  69. blank=True,
  70. verbose_name='研究方向',
  71. help_text='用逗号分隔多个方向(如:人工智能,教育技术)'
  72. )
  73. skill_tags = models.CharField(
  74. max_length=255,
  75. blank=True,
  76. verbose_name='技能标签',
  77. help_text='用逗号分隔多个技能(如:Python,数据分析)'
  78. )
  79. class Meta:
  80. db_table = 'user_academic_profile'
  81. verbose_name = '学术档案'
  82. verbose_name_plural = "学术档案"
  83. def __str__(self):
  84. return f"{self.user.name}的学术档案"
  85. class ResearchGroup(models.Model):
  86. """教研小组模型"""
  87. group_id = models.AutoField(primary_key=True, verbose_name="小组ID")
  88. name = models.CharField(max_length=100, unique=True, verbose_name="小组名称")
  89. description = models.TextField(blank=True, verbose_name="小组描述")
  90. created_by = models.ForeignKey(
  91. Users,
  92. on_delete=models.SET_NULL,
  93. null=True,
  94. related_name='created_groups',
  95. verbose_name="创建人"
  96. )
  97. created_at = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
  98. is_active = models.BooleanField(default=True, verbose_name="是否活跃")
  99. class Meta:
  100. db_table = 'user_research_group'
  101. verbose_name = '教研小组'
  102. verbose_name_plural = "教研小组"
  103. ordering = ['-created_at']
  104. def __str__(self):
  105. return f"{self.name}(ID:{self.group_id})"
  106. class GroupMembership(models.Model):
  107. """小组成员关联模型"""
  108. class MemberRole(models.TextChoices):
  109. LEADER = 'LEAD', _('组长')
  110. DEPUTY = 'DEP', _('副组长')
  111. CORE = 'CORE', _('核心成员')
  112. MEMBER = 'MEM', _('普通成员')
  113. ADVISOR = 'ADV', _('指导老师')
  114. OBSERVER = 'OBS', _('观察员')
  115. class MemberStatus(models.TextChoices):
  116. ACTIVE = 'ACT', _('活跃')
  117. LEAVE = 'LV', _('请假')
  118. INACTIVE = 'INAC', _('不活跃')
  119. GRADUATED = 'GRAD', _('已毕业')
  120. TRANSFERRED = 'TRF', _('已转组')
  121. user = models.ForeignKey(
  122. Users,
  123. on_delete=models.CASCADE,
  124. related_name='group_memberships',
  125. verbose_name="成员"
  126. )
  127. group = models.ForeignKey(
  128. ResearchGroup,
  129. on_delete=models.CASCADE,
  130. related_name='members',
  131. verbose_name="所属小组"
  132. )
  133. role = models.CharField(
  134. max_length=20,
  135. choices=MemberRole.choices,
  136. default=MemberRole.MEMBER,
  137. verbose_name="小组角色"
  138. )
  139. status = models.CharField(
  140. max_length=10,
  141. choices=MemberStatus.choices,
  142. default=MemberStatus.ACTIVE,
  143. verbose_name="在组状态"
  144. )
  145. joined_at = models.DateTimeField(auto_now_add=True, verbose_name="加入时间")
  146. left_at = models.DateTimeField(null=True, blank=True, verbose_name="离开时间")
  147. custom_permissions = models.JSONField(
  148. null=True,
  149. blank=True,
  150. default=dict,
  151. verbose_name="特殊权限",
  152. help_text="JSON格式存储额外权限"
  153. )
  154. class Meta:
  155. db_table = 'user_group_membership'
  156. verbose_name = '小组成员'
  157. verbose_name_plural = "小组成员"
  158. unique_together = ('user', 'group') # 确保同一用户不会重复加入同一小组
  159. ordering = ['-joined_at']
  160. def save(self, *args, **kwargs):
  161. """自动更新离开时间"""
  162. if self.status in [self.MemberStatus.GRADUATED, self.MemberStatus.TRANSFERRED] and not self.left_at:
  163. self.left_at = timezone.now()
  164. super().save(*args, **kwargs)
  165. def __str__(self):
  166. return f"{self.user.name}在{self.group.name}({self.get_role_display()})"