from django.db import models from django.conf import settings # 用于引用 AUTH_USER_MODEL from django.utils.translation import gettext_lazy as _ # 我们可以让小组也关联到兴趣标签 # from accounts.models import InterestTag # 如果你想直接引用 class Group(models.Model): name = models.CharField(_('小组名称'), max_length=100, unique=True) description = models.TextField(_('小组描述'), blank=True) cover_image = models.ImageField(_('小组封面'), upload_to='group_covers/', null=True, blank=True) creator = models.ForeignKey( settings.AUTH_USER_MODEL, # 关联到你的CustomUser模型 verbose_name=_('创建者'), on_delete=models.SET_NULL, # 如果创建者被删除,小组可以保留,或者设为CASCADE则一起删除 null=True, # 允许创建者为空 (虽然通常不希望这样,但SET_NULL要求) related_name='created_groups' ) members = models.ManyToManyField( settings.AUTH_USER_MODEL, through='Membership', # 通过我们下面定义的Membership模型来管理成员关系 through_fields=('group', 'user'), # 指定Membership模型中关联Group和User的字段名 verbose_name=_('小组成员'), blank=True, # 小组刚创建时可以没有成员 (创建者会自动成为第一个成员) related_name='joined_groups' ) # 关联到兴趣标签 (可选,但对推荐小组有帮助) tags = models.ManyToManyField( 'accounts.InterestTag', # 引用 accounts 应用的 InterestTag 模型 verbose_name=_('相关兴趣标签'), blank=True, related_name='groups_with_tag' ) created_at = models.DateTimeField(auto_now_add=True, verbose_name=_('创建时间')) updated_at = models.DateTimeField(auto_now=True, verbose_name=_('更新时间')) # (可选) 小组类型:公开、私密等 # PUBLIC = 'public' # PRIVATE = 'private' # GROUP_TYPE_CHOICES = [ # (PUBLIC, _('公开小组')), # (PRIVATE, _('私密小组')), # ] # group_type = models.CharField( # max_length=10, # choices=GROUP_TYPE_CHOICES, # default=PUBLIC, # verbose_name=_('小组类型') # ) class Meta: verbose_name = _('小组') verbose_name_plural = _('小组们') ordering = ['-created_at'] # 按创建时间降序排列 def __str__(self): return self.name class Membership(models.Model): """ 用户和小组之间的中间模型,用于存储额外的成员关系信息。 """ user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, verbose_name=_('用户')) group = models.ForeignKey(Group, on_delete=models.CASCADE, verbose_name=_('小组')) date_joined = models.DateTimeField(auto_now_add=True, verbose_name=_('加入日期')) # (可选) 成员角色 # MEMBER = 'member' # ADMIN = 'admin' # MODERATOR = 'moderator' # ROLE_CHOICES = [ # (MEMBER, _('成员')), # (ADMIN, _('管理员')), # (MODERATOR, _('版主')), # ] # role = models.CharField( # max_length=10, # choices=ROLE_CHOICES, # default=MEMBER, # verbose_name=_('角色') # ) class Post(models.Model): group = models.ForeignKey( Group, on_delete=models.CASCADE, # 如果小组被删除,该小组下的所有帖子也一并删除 related_name='posts', # 允许通过 group_instance.posts.all() 获取小组所有帖子 verbose_name=_('所属小组') ) author = models.ForeignKey( settings.AUTH_USER_MODEL, # 关联到 CustomUser 模型 on_delete=models.CASCADE, # 如果发帖用户被删除,其帖子也一并删除 (你也可以考虑SET_NULL) related_name='posts', # 允许通过 user_instance.posts.all() 获取用户所有帖子 verbose_name=_('作者') ) title = models.CharField(_('帖子标题'), max_length=200, blank=True, null=True) # 帖子可以有标题,也可以没有(类似动态) content = models.TextField(_('帖子内容')) # (可选) 帖子图片或附件,可以用 ImageField 或 FileField,或者更复杂的方案如多图片关联 # image = models.ImageField(_('帖子图片'), upload_to='post_images/', null=True, blank=True) created_at = models.DateTimeField(auto_now_add=True, verbose_name=_('发布时间')) updated_at = models.DateTimeField(auto_now=True, verbose_name=_('更新时间')) # (可选) 点赞数、评论数等统计字段,可以通过 annotate 动态获取,或在这里冗余存储以提高查询性能 # likes_count = models.PositiveIntegerField(default=0, verbose_name=_('点赞数')) # comments_count = models.PositiveIntegerField(default=0, verbose_name=_('评论数')) class Meta: verbose_name = _('帖子/动态') verbose_name_plural = _('帖子/动态们') ordering = ['-created_at'] # 默认按发布时间降序排列 (最新的在前面) def __str__(self): return self.title if self.title else f"帖子来自 {self.author.display_name} 在 {self.group.name}" # 为了上面的 __str__ 方法,我们可能需要在 CustomUser 模型中添加一个辅助方法 # 打开 accounts/models.py,在 CustomUser 类中添加: # def nickname_or_email(self): # return self.nickname if self.nickname else self.email # CustomUser.add_to_class("nickname_or_email", nickname_or_email) # 如果想动态添加 # 或者直接在 __str__ 中写: # return f"{self.user.nickname if self.user.nickname else self.user.email} 加入了 {self.group.name}"