models.py 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. from django.db import models
  2. from django.conf import settings # 用于引用 AUTH_USER_MODEL
  3. from django.utils.translation import gettext_lazy as _
  4. # 我们可以让小组也关联到兴趣标签
  5. # from accounts.models import InterestTag # 如果你想直接引用
  6. class Group(models.Model):
  7. name = models.CharField(_('小组名称'), max_length=100, unique=True)
  8. description = models.TextField(_('小组描述'), blank=True)
  9. cover_image = models.ImageField(_('小组封面'), upload_to='group_covers/', null=True, blank=True)
  10. creator = models.ForeignKey(
  11. settings.AUTH_USER_MODEL, # 关联到你的CustomUser模型
  12. verbose_name=_('创建者'),
  13. on_delete=models.SET_NULL, # 如果创建者被删除,小组可以保留,或者设为CASCADE则一起删除
  14. null=True, # 允许创建者为空 (虽然通常不希望这样,但SET_NULL要求)
  15. related_name='created_groups'
  16. )
  17. members = models.ManyToManyField(
  18. settings.AUTH_USER_MODEL,
  19. through='Membership', # 通过我们下面定义的Membership模型来管理成员关系
  20. through_fields=('group', 'user'), # 指定Membership模型中关联Group和User的字段名
  21. verbose_name=_('小组成员'),
  22. blank=True, # 小组刚创建时可以没有成员 (创建者会自动成为第一个成员)
  23. related_name='joined_groups'
  24. )
  25. # 关联到兴趣标签 (可选,但对推荐小组有帮助)
  26. tags = models.ManyToManyField(
  27. 'accounts.InterestTag', # 引用 accounts 应用的 InterestTag 模型
  28. verbose_name=_('相关兴趣标签'),
  29. blank=True,
  30. related_name='groups_with_tag'
  31. )
  32. created_at = models.DateTimeField(auto_now_add=True, verbose_name=_('创建时间'))
  33. updated_at = models.DateTimeField(auto_now=True, verbose_name=_('更新时间'))
  34. # (可选) 小组类型:公开、私密等
  35. # PUBLIC = 'public'
  36. # PRIVATE = 'private'
  37. # GROUP_TYPE_CHOICES = [
  38. # (PUBLIC, _('公开小组')),
  39. # (PRIVATE, _('私密小组')),
  40. # ]
  41. # group_type = models.CharField(
  42. # max_length=10,
  43. # choices=GROUP_TYPE_CHOICES,
  44. # default=PUBLIC,
  45. # verbose_name=_('小组类型')
  46. # )
  47. class Meta:
  48. verbose_name = _('小组')
  49. verbose_name_plural = _('小组们')
  50. ordering = ['-created_at'] # 按创建时间降序排列
  51. def __str__(self):
  52. return self.name
  53. class Membership(models.Model):
  54. """
  55. 用户和小组之间的中间模型,用于存储额外的成员关系信息。
  56. """
  57. user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, verbose_name=_('用户'))
  58. group = models.ForeignKey(Group, on_delete=models.CASCADE, verbose_name=_('小组'))
  59. date_joined = models.DateTimeField(auto_now_add=True, verbose_name=_('加入日期'))
  60. # (可选) 成员角色
  61. # MEMBER = 'member'
  62. # ADMIN = 'admin'
  63. # MODERATOR = 'moderator'
  64. # ROLE_CHOICES = [
  65. # (MEMBER, _('成员')),
  66. # (ADMIN, _('管理员')),
  67. # (MODERATOR, _('版主')),
  68. # ]
  69. # role = models.CharField(
  70. # max_length=10,
  71. # choices=ROLE_CHOICES,
  72. # default=MEMBER,
  73. # verbose_name=_('角色')
  74. # )
  75. class Post(models.Model):
  76. group = models.ForeignKey(
  77. Group,
  78. on_delete=models.CASCADE, # 如果小组被删除,该小组下的所有帖子也一并删除
  79. related_name='posts', # 允许通过 group_instance.posts.all() 获取小组所有帖子
  80. verbose_name=_('所属小组')
  81. )
  82. author = models.ForeignKey(
  83. settings.AUTH_USER_MODEL, # 关联到 CustomUser 模型
  84. on_delete=models.CASCADE, # 如果发帖用户被删除,其帖子也一并删除 (你也可以考虑SET_NULL)
  85. related_name='posts', # 允许通过 user_instance.posts.all() 获取用户所有帖子
  86. verbose_name=_('作者')
  87. )
  88. title = models.CharField(_('帖子标题'), max_length=200, blank=True, null=True) # 帖子可以有标题,也可以没有(类似动态)
  89. content = models.TextField(_('帖子内容'))
  90. # (可选) 帖子图片或附件,可以用 ImageField 或 FileField,或者更复杂的方案如多图片关联
  91. # image = models.ImageField(_('帖子图片'), upload_to='post_images/', null=True, blank=True)
  92. created_at = models.DateTimeField(auto_now_add=True, verbose_name=_('发布时间'))
  93. updated_at = models.DateTimeField(auto_now=True, verbose_name=_('更新时间'))
  94. # (可选) 点赞数、评论数等统计字段,可以通过 annotate 动态获取,或在这里冗余存储以提高查询性能
  95. # likes_count = models.PositiveIntegerField(default=0, verbose_name=_('点赞数'))
  96. # comments_count = models.PositiveIntegerField(default=0, verbose_name=_('评论数'))
  97. class Meta:
  98. verbose_name = _('帖子/动态')
  99. verbose_name_plural = _('帖子/动态们')
  100. ordering = ['-created_at'] # 默认按发布时间降序排列 (最新的在前面)
  101. def __str__(self):
  102. return self.title if self.title else f"帖子来自 {self.author.display_name} 在 {self.group.name}"
  103. # 为了上面的 __str__ 方法,我们可能需要在 CustomUser 模型中添加一个辅助方法
  104. # 打开 accounts/models.py,在 CustomUser 类中添加:
  105. # def nickname_or_email(self):
  106. # return self.nickname if self.nickname else self.email
  107. # CustomUser.add_to_class("nickname_or_email", nickname_or_email) # 如果想动态添加
  108. # 或者直接在 __str__ 中写:
  109. # return f"{self.user.nickname if self.user.nickname else self.user.email} 加入了 {self.group.name}"