models.py 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  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. from django.utils import timezone
  5. class Group(models.Model):
  6. name = models.CharField(_('小组名称'), max_length=100, unique=True)
  7. description = models.TextField(_('小组描述'), blank=True)
  8. cover_image = models.ImageField(_('小组封面'), upload_to='group_covers/', null=True, blank=True)
  9. creator = models.ForeignKey(
  10. settings.AUTH_USER_MODEL,
  11. verbose_name=_('创建者'),
  12. on_delete=models.SET_NULL,
  13. null=True,
  14. related_name='created_groups'
  15. )
  16. members = models.ManyToManyField(
  17. settings.AUTH_USER_MODEL,
  18. through='Membership',
  19. through_fields=('group', 'user'),
  20. verbose_name=_('小组成员'),
  21. blank=True,
  22. related_name='joined_groups'
  23. )
  24. tags = models.ManyToManyField(
  25. 'accounts.InterestTag',
  26. verbose_name=_('相关兴趣标签'),
  27. blank=True,
  28. related_name='groups_with_tag'
  29. )
  30. created_at = models.DateTimeField(auto_now_add=True, verbose_name=_('创建时间'))
  31. updated_at = models.DateTimeField(auto_now=True, verbose_name=_('更新时间'))
  32. class Meta:
  33. verbose_name = _('小组')
  34. verbose_name_plural = _('小组们')
  35. ordering = ['-created_at']
  36. def __str__(self):
  37. return self.name
  38. class Membership(models.Model):
  39. user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, verbose_name=_('用户'))
  40. group = models.ForeignKey(Group, on_delete=models.CASCADE, verbose_name=_('小组'))
  41. date_joined = models.DateTimeField(auto_now_add=True, verbose_name=_('加入日期'))
  42. class Meta:
  43. verbose_name = _('小组成员关系')
  44. verbose_name_plural = _('小组成员关系们')
  45. unique_together = ('user', 'group')
  46. ordering = ['-date_joined']
  47. def __str__(self):
  48. user_identifier = self.user.email
  49. if hasattr(self.user, 'display_name') and self.user.display_name:
  50. user_identifier = self.user.display_name
  51. elif hasattr(self.user, 'nickname') and self.user.nickname:
  52. user_identifier = self.user.nickname
  53. return f"{user_identifier} 加入了 {self.group.name}"
  54. class Post(models.Model):
  55. group = models.ForeignKey(
  56. Group,
  57. on_delete=models.CASCADE,
  58. related_name='posts',
  59. verbose_name=_('所属小组')
  60. )
  61. author = models.ForeignKey(
  62. settings.AUTH_USER_MODEL,
  63. on_delete=models.CASCADE,
  64. related_name='%(app_label)s_posts',
  65. verbose_name=_('作者')
  66. )
  67. title = models.CharField(_('帖子标题'), max_length=200, blank=True, null=True)
  68. content = models.TextField(_('帖子内容'))
  69. created_at = models.DateTimeField(auto_now_add=True, verbose_name=_('发布时间'))
  70. updated_at = models.DateTimeField(auto_now=True, verbose_name=_('更新时间'))
  71. class Meta:
  72. verbose_name = _('帖子/动态')
  73. verbose_name_plural = _('帖子/动态们')
  74. ordering = ['-created_at']
  75. def __str__(self):
  76. author_identifier = self.author.email
  77. if hasattr(self.author, 'display_name') and self.author.display_name:
  78. author_identifier = self.author.display_name
  79. elif hasattr(self.author, 'nickname') and self.author.nickname:
  80. author_identifier = self.author.nickname
  81. title_part = f"'{self.title}'" if self.title else f"动态来自 {author_identifier}"
  82. return f"{title_part} 在小组 '{self.group.name}'"
  83. class Comment(models.Model):
  84. post = models.ForeignKey(
  85. Post,
  86. on_delete=models.CASCADE,
  87. related_name='comments',
  88. verbose_name=_('所属帖子')
  89. )
  90. author = models.ForeignKey(
  91. settings.AUTH_USER_MODEL,
  92. on_delete=models.CASCADE,
  93. related_name='%(app_label)s_comments',
  94. verbose_name=_('评论作者')
  95. )
  96. content = models.TextField(_('评论内容'))
  97. created_at = models.DateTimeField(auto_now_add=True, verbose_name=_('评论时间'))
  98. updated_at = models.DateTimeField(auto_now=True, verbose_name=_('更新时间'))
  99. class Meta:
  100. verbose_name = _('评论')
  101. verbose_name_plural = _('评论们')
  102. ordering = ['created_at']
  103. def __str__(self):
  104. author_identifier = self.author.email
  105. if hasattr(self.author, 'display_name') and self.author.display_name:
  106. author_identifier = self.author.display_name
  107. elif hasattr(self.author, 'nickname') and self.author.nickname:
  108. author_identifier = self.author.nickname
  109. post_identifier = self.post.title if self.post.title else f"帖子ID({self.post.id})"
  110. content_preview = (self.content[:30] + '...') if len(self.content) > 30 else self.content
  111. return f"{author_identifier} 对 '{post_identifier}' 的评论: \"{content_preview}\""
  112. class PostLike(models.Model): # <<<< 新增 PostLike 模型
  113. user = models.ForeignKey(
  114. settings.AUTH_USER_MODEL,
  115. on_delete=models.CASCADE,
  116. related_name='post_likes',
  117. verbose_name=_('点赞用户')
  118. )
  119. post = models.ForeignKey(
  120. Post,
  121. on_delete=models.CASCADE,
  122. related_name='likes', # 允许 post.likes.count()
  123. verbose_name=_('被点赞的帖子')
  124. )
  125. created_at = models.DateTimeField(auto_now_add=True, verbose_name=_('点赞时间'))
  126. class Meta:
  127. verbose_name = _('帖子点赞')
  128. verbose_name_plural = _('帖子点赞们')
  129. unique_together = ('user', 'post') # 核心:确保用户对帖子只能点赞一次
  130. ordering = ['-created_at']
  131. def __str__(self):
  132. user_identifier = self.user.email
  133. if hasattr(self.user, 'display_name') and self.user.display_name:
  134. user_identifier = self.user.display_name
  135. elif hasattr(self.user, 'nickname') and self.user.nickname:
  136. user_identifier = self.user.nickname
  137. post_identifier = self.post.title if self.post.title else f"帖子ID({self.post.id})"
  138. return f"{user_identifier} 点赞了 '{post_identifier}'"