|
@@ -1,31 +1,29 @@
|
|
from django.db import models
|
|
from django.db import models
|
|
from django.conf import settings # 用于引用 AUTH_USER_MODEL
|
|
from django.conf import settings # 用于引用 AUTH_USER_MODEL
|
|
from django.utils.translation import gettext_lazy as _
|
|
from django.utils.translation import gettext_lazy as _
|
|
-# 我们可以让小组也关联到兴趣标签
|
|
|
|
-# from accounts.models import InterestTag # 如果你想直接引用
|
|
|
|
|
|
+from django.utils import timezone
|
|
|
|
|
|
class Group(models.Model):
|
|
class Group(models.Model):
|
|
name = models.CharField(_('小组名称'), max_length=100, unique=True)
|
|
name = models.CharField(_('小组名称'), max_length=100, unique=True)
|
|
description = models.TextField(_('小组描述'), blank=True)
|
|
description = models.TextField(_('小组描述'), blank=True)
|
|
cover_image = models.ImageField(_('小组封面'), upload_to='group_covers/', null=True, blank=True)
|
|
cover_image = models.ImageField(_('小组封面'), upload_to='group_covers/', null=True, blank=True)
|
|
creator = models.ForeignKey(
|
|
creator = models.ForeignKey(
|
|
- settings.AUTH_USER_MODEL, # 关联到你的CustomUser模型
|
|
|
|
|
|
+ settings.AUTH_USER_MODEL,
|
|
verbose_name=_('创建者'),
|
|
verbose_name=_('创建者'),
|
|
- on_delete=models.SET_NULL, # 如果创建者被删除,小组可以保留,或者设为CASCADE则一起删除
|
|
|
|
- null=True, # 允许创建者为空 (虽然通常不希望这样,但SET_NULL要求)
|
|
|
|
|
|
+ on_delete=models.SET_NULL,
|
|
|
|
+ null=True,
|
|
related_name='created_groups'
|
|
related_name='created_groups'
|
|
)
|
|
)
|
|
members = models.ManyToManyField(
|
|
members = models.ManyToManyField(
|
|
settings.AUTH_USER_MODEL,
|
|
settings.AUTH_USER_MODEL,
|
|
- through='Membership', # 通过我们下面定义的Membership模型来管理成员关系
|
|
|
|
- through_fields=('group', 'user'), # 指定Membership模型中关联Group和User的字段名
|
|
|
|
|
|
+ through='Membership',
|
|
|
|
+ through_fields=('group', 'user'),
|
|
verbose_name=_('小组成员'),
|
|
verbose_name=_('小组成员'),
|
|
- blank=True, # 小组刚创建时可以没有成员 (创建者会自动成为第一个成员)
|
|
|
|
|
|
+ blank=True,
|
|
related_name='joined_groups'
|
|
related_name='joined_groups'
|
|
)
|
|
)
|
|
- # 关联到兴趣标签 (可选,但对推荐小组有帮助)
|
|
|
|
tags = models.ManyToManyField(
|
|
tags = models.ManyToManyField(
|
|
- 'accounts.InterestTag', # 引用 accounts 应用的 InterestTag 模型
|
|
|
|
|
|
+ 'accounts.InterestTag',
|
|
verbose_name=_('相关兴趣标签'),
|
|
verbose_name=_('相关兴趣标签'),
|
|
blank=True,
|
|
blank=True,
|
|
related_name='groups_with_tag'
|
|
related_name='groups_with_tag'
|
|
@@ -33,87 +31,124 @@ class Group(models.Model):
|
|
created_at = models.DateTimeField(auto_now_add=True, verbose_name=_('创建时间'))
|
|
created_at = models.DateTimeField(auto_now_add=True, verbose_name=_('创建时间'))
|
|
updated_at = models.DateTimeField(auto_now=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:
|
|
class Meta:
|
|
verbose_name = _('小组')
|
|
verbose_name = _('小组')
|
|
verbose_name_plural = _('小组们')
|
|
verbose_name_plural = _('小组们')
|
|
- ordering = ['-created_at'] # 按创建时间降序排列
|
|
|
|
|
|
+ ordering = ['-created_at']
|
|
|
|
|
|
def __str__(self):
|
|
def __str__(self):
|
|
return self.name
|
|
return self.name
|
|
|
|
|
|
class Membership(models.Model):
|
|
class Membership(models.Model):
|
|
- """
|
|
|
|
- 用户和小组之间的中间模型,用于存储额外的成员关系信息。
|
|
|
|
- """
|
|
|
|
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, verbose_name=_('用户'))
|
|
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, verbose_name=_('用户'))
|
|
group = models.ForeignKey(Group, 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=_('加入日期'))
|
|
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 Meta:
|
|
|
|
+ verbose_name = _('小组成员关系')
|
|
|
|
+ verbose_name_plural = _('小组成员关系们')
|
|
|
|
+ unique_together = ('user', 'group')
|
|
|
|
+ ordering = ['-date_joined']
|
|
|
|
+
|
|
|
|
+ def __str__(self):
|
|
|
|
+ user_identifier = self.user.email
|
|
|
|
+ if hasattr(self.user, 'display_name') and self.user.display_name:
|
|
|
|
+ user_identifier = self.user.display_name
|
|
|
|
+ elif hasattr(self.user, 'nickname') and self.user.nickname:
|
|
|
|
+ user_identifier = self.user.nickname
|
|
|
|
+ return f"{user_identifier} 加入了 {self.group.name}"
|
|
|
|
+
|
|
class Post(models.Model):
|
|
class Post(models.Model):
|
|
group = models.ForeignKey(
|
|
group = models.ForeignKey(
|
|
Group,
|
|
Group,
|
|
- on_delete=models.CASCADE, # 如果小组被删除,该小组下的所有帖子也一并删除
|
|
|
|
- related_name='posts', # 允许通过 group_instance.posts.all() 获取小组所有帖子
|
|
|
|
|
|
+ on_delete=models.CASCADE,
|
|
|
|
+ related_name='posts',
|
|
verbose_name=_('所属小组')
|
|
verbose_name=_('所属小组')
|
|
)
|
|
)
|
|
author = models.ForeignKey(
|
|
author = models.ForeignKey(
|
|
- settings.AUTH_USER_MODEL, # 关联到 CustomUser 模型
|
|
|
|
- on_delete=models.CASCADE, # 如果发帖用户被删除,其帖子也一并删除 (你也可以考虑SET_NULL)
|
|
|
|
- related_name='posts', # 允许通过 user_instance.posts.all() 获取用户所有帖子
|
|
|
|
|
|
+ settings.AUTH_USER_MODEL,
|
|
|
|
+ on_delete=models.CASCADE,
|
|
|
|
+ related_name='%(app_label)s_posts',
|
|
verbose_name=_('作者')
|
|
verbose_name=_('作者')
|
|
)
|
|
)
|
|
- title = models.CharField(_('帖子标题'), max_length=200, blank=True, null=True) # 帖子可以有标题,也可以没有(类似动态)
|
|
|
|
|
|
+ title = models.CharField(_('帖子标题'), max_length=200, blank=True, null=True)
|
|
content = models.TextField(_('帖子内容'))
|
|
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=_('发布时间'))
|
|
created_at = models.DateTimeField(auto_now_add=True, verbose_name=_('发布时间'))
|
|
updated_at = models.DateTimeField(auto_now=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:
|
|
class Meta:
|
|
verbose_name = _('帖子/动态')
|
|
verbose_name = _('帖子/动态')
|
|
verbose_name_plural = _('帖子/动态们')
|
|
verbose_name_plural = _('帖子/动态们')
|
|
- ordering = ['-created_at'] # 默认按发布时间降序排列 (最新的在前面)
|
|
|
|
|
|
+ ordering = ['-created_at']
|
|
|
|
+
|
|
|
|
+ def __str__(self):
|
|
|
|
+ author_identifier = self.author.email
|
|
|
|
+ if hasattr(self.author, 'display_name') and self.author.display_name:
|
|
|
|
+ author_identifier = self.author.display_name
|
|
|
|
+ elif hasattr(self.author, 'nickname') and self.author.nickname:
|
|
|
|
+ author_identifier = self.author.nickname
|
|
|
|
+ title_part = f"'{self.title}'" if self.title else f"动态来自 {author_identifier}"
|
|
|
|
+ return f"{title_part} 在小组 '{self.group.name}'"
|
|
|
|
+
|
|
|
|
+class Comment(models.Model):
|
|
|
|
+ post = models.ForeignKey(
|
|
|
|
+ Post,
|
|
|
|
+ on_delete=models.CASCADE,
|
|
|
|
+ related_name='comments',
|
|
|
|
+ verbose_name=_('所属帖子')
|
|
|
|
+ )
|
|
|
|
+ author = models.ForeignKey(
|
|
|
|
+ settings.AUTH_USER_MODEL,
|
|
|
|
+ on_delete=models.CASCADE,
|
|
|
|
+ related_name='%(app_label)s_comments',
|
|
|
|
+ verbose_name=_('评论作者')
|
|
|
|
+ )
|
|
|
|
+ content = models.TextField(_('评论内容'))
|
|
|
|
+ created_at = models.DateTimeField(auto_now_add=True, verbose_name=_('评论时间'))
|
|
|
|
+ updated_at = models.DateTimeField(auto_now=True, verbose_name=_('更新时间'))
|
|
|
|
+
|
|
|
|
+ class Meta:
|
|
|
|
+ verbose_name = _('评论')
|
|
|
|
+ verbose_name_plural = _('评论们')
|
|
|
|
+ ordering = ['created_at']
|
|
|
|
+
|
|
|
|
+ def __str__(self):
|
|
|
|
+ author_identifier = self.author.email
|
|
|
|
+ if hasattr(self.author, 'display_name') and self.author.display_name:
|
|
|
|
+ author_identifier = self.author.display_name
|
|
|
|
+ elif hasattr(self.author, 'nickname') and self.author.nickname:
|
|
|
|
+ author_identifier = self.author.nickname
|
|
|
|
+ post_identifier = self.post.title if self.post.title else f"帖子ID({self.post.id})"
|
|
|
|
+ content_preview = (self.content[:30] + '...') if len(self.content) > 30 else self.content
|
|
|
|
+ return f"{author_identifier} 对 '{post_identifier}' 的评论: \"{content_preview}\""
|
|
|
|
+
|
|
|
|
+class PostLike(models.Model): # <<<< 新增 PostLike 模型
|
|
|
|
+ user = models.ForeignKey(
|
|
|
|
+ settings.AUTH_USER_MODEL,
|
|
|
|
+ on_delete=models.CASCADE,
|
|
|
|
+ related_name='post_likes',
|
|
|
|
+ verbose_name=_('点赞用户')
|
|
|
|
+ )
|
|
|
|
+ post = models.ForeignKey(
|
|
|
|
+ Post,
|
|
|
|
+ on_delete=models.CASCADE,
|
|
|
|
+ related_name='likes', # 允许 post.likes.count()
|
|
|
|
+ verbose_name=_('被点赞的帖子')
|
|
|
|
+ )
|
|
|
|
+ created_at = models.DateTimeField(auto_now_add=True, verbose_name=_('点赞时间'))
|
|
|
|
+
|
|
|
|
+ class Meta:
|
|
|
|
+ verbose_name = _('帖子点赞')
|
|
|
|
+ verbose_name_plural = _('帖子点赞们')
|
|
|
|
+ unique_together = ('user', 'post') # 核心:确保用户对帖子只能点赞一次
|
|
|
|
+ ordering = ['-created_at']
|
|
|
|
|
|
def __str__(self):
|
|
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}"
|
|
|
|
|
|
+ user_identifier = self.user.email
|
|
|
|
+ if hasattr(self.user, 'display_name') and self.user.display_name:
|
|
|
|
+ user_identifier = self.user.display_name
|
|
|
|
+ elif hasattr(self.user, 'nickname') and self.user.nickname:
|
|
|
|
+ user_identifier = self.user.nickname
|
|
|
|
+
|
|
|
|
+ post_identifier = self.post.title if self.post.title else f"帖子ID({self.post.id})"
|
|
|
|
+ return f"{user_identifier} 点赞了 '{post_identifier}'"
|