Files
market_page/backend/community/models.py
jeremygan2021 752b7caf71 finish
2026-02-11 15:03:22 +08:00

175 lines
7.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from django.db import models
from shop.models import WeChatUser, ESP32Config, Order, Service, VCCourse, ServiceOrder
class Activity(models.Model):
"""
社区活动模型
"""
title = models.CharField(max_length=100, verbose_name="活动标题")
description = models.TextField(verbose_name="活动详情")
banner = models.ImageField(upload_to='activities/banners/', verbose_name="活动Banner图", null=True, blank=True)
banner_url = models.URLField(verbose_name="活动Banner链接", null=True, blank=True, help_text="可直接填写图片链接,若同时上传图片,将优先显示上传的图片")
start_time = models.DateTimeField(verbose_name="开始时间")
end_time = models.DateTimeField(verbose_name="结束时间")
location = models.CharField(max_length=100, verbose_name="活动地点")
max_participants = models.IntegerField(default=50, verbose_name="最大报名人数")
is_active = models.BooleanField(default=True, verbose_name="是否启用")
created_at = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
def clean(self):
from django.core.exceptions import ValidationError
if not self.banner and not self.banner_url:
raise ValidationError("Banner图片和Banner链接必须至少填写一项")
def save(self, *args, **kwargs):
self.clean()
super().save(*args, **kwargs)
@property
def display_banner_url(self):
"""
获取Banner显示的URL优先使用上传的图片
"""
if self.banner:
return self.banner.url
return self.banner_url
def __str__(self):
return self.title
class Meta:
verbose_name = "社区活动"
verbose_name_plural = "社区活动管理"
class ActivitySignup(models.Model):
"""
活动报名记录
"""
STATUS_CHOICES = (
('pending', '审核中'),
('confirmed', '报名成功'),
('cancelled', '已取消'),
)
activity = models.ForeignKey(Activity, on_delete=models.CASCADE, related_name='signups', verbose_name="活动")
user = models.ForeignKey(WeChatUser, on_delete=models.CASCADE, related_name='activity_signups', verbose_name="报名用户")
signup_time = models.DateTimeField(auto_now_add=True, verbose_name="报名时间")
status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='confirmed', verbose_name="状态")
def __str__(self):
return f"{self.user.nickname} - {self.activity.title}"
class Meta:
verbose_name = "活动报名"
verbose_name_plural = "活动报名管理"
unique_together = ('activity', 'user')
class Topic(models.Model):
"""
论坛帖子/主题
"""
title = models.CharField(max_length=200, verbose_name="标题")
content = models.TextField(verbose_name="内容", help_text="支持Markdown格式支持插入图片")
author = models.ForeignKey(WeChatUser, on_delete=models.CASCADE, related_name='topics', verbose_name="作者")
# 关联对象:硬件、服务、课程
related_product = models.ForeignKey(ESP32Config, on_delete=models.SET_NULL, null=True, blank=True, verbose_name="关联硬件")
related_service = models.ForeignKey(Service, on_delete=models.SET_NULL, null=True, blank=True, verbose_name="关联服务")
related_course = models.ForeignKey(VCCourse, on_delete=models.SET_NULL, null=True, blank=True, verbose_name="关联课程")
view_count = models.IntegerField(default=0, verbose_name="浏览量")
is_pinned = models.BooleanField(default=False, verbose_name="置顶")
created_at = models.DateTimeField(auto_now_add=True, verbose_name="发布时间")
updated_at = models.DateTimeField(auto_now=True, verbose_name="更新时间")
def __str__(self):
return self.title
@property
def is_verified_owner(self):
"""
判断作者是否为关联项目(硬件/服务/课程的已购用户Verified Owner
"""
# 1. 验证硬件
if self.related_product:
if Order.objects.filter(
wechat_user=self.author,
config=self.related_product,
status__in=['paid', 'shipped']
).exists():
return True
# 2. 验证课程
if self.related_course:
if Order.objects.filter(
wechat_user=self.author,
course=self.related_course,
status__in=['paid', 'shipped']
).exists():
return True
# 3. 验证服务
if self.related_service:
# ServiceOrder 模型中没有 direct link to WeChatUser (only phone/name),
# 但我们假设通过手机号或未来关联来验证,目前先检查 ServiceOrder 是否有对应记录。
# 由于 ServiceOrder 目前设计没有直接关联 WeChatUser 字段,我们暂时尝试通过名字或后续改进。
# 经检查 shop/models.py, ServiceOrder 确实只有 customer_name/phone_number.
# 这里为了严谨,我们暂时仅对有关联的进行检查,或者需要改进 ServiceOrder。
# 鉴于当前任务范围,如果 ServiceOrder 没有 user 字段,我们可能无法精确验证,
# 除非我们假设用户填写的手机号与微信用户关联。
# *修正*: 为了快速实现,我们先跳过 ServiceOrder 的精确验证,或者仅仅返回 False
# 等待后续 ServiceOrder 添加 wechat_user 字段。
pass
return False
class Meta:
verbose_name = "论坛帖子"
verbose_name_plural = "论坛帖子管理"
ordering = ['-is_pinned', '-created_at']
class Reply(models.Model):
"""
帖子回复
"""
topic = models.ForeignKey(Topic, on_delete=models.CASCADE, related_name='replies', verbose_name="所属帖子")
content = models.TextField(verbose_name="回复内容", help_text="支持Markdown格式")
author = models.ForeignKey(WeChatUser, on_delete=models.CASCADE, related_name='replies', verbose_name="回复者")
reply_to = models.ForeignKey('self', on_delete=models.SET_NULL, null=True, blank=True, related_name='children', verbose_name="回复楼层")
created_at = models.DateTimeField(auto_now_add=True, verbose_name="回复时间")
def __str__(self):
return f"回复: {self.topic.title}"
class Meta:
verbose_name = "帖子回复"
verbose_name_plural = "帖子回复管理"
ordering = ['created_at']
class TopicMedia(models.Model):
"""
论坛多媒体资源(图片/视频/文件)
"""
MEDIA_TYPE_CHOICES = (
('image', '图片'),
('video', '视频'),
('file', '文件'),
)
topic = models.ForeignKey(Topic, on_delete=models.CASCADE, related_name='media', verbose_name="所属帖子", null=True, blank=True)
reply = models.ForeignKey(Reply, on_delete=models.CASCADE, related_name='media', verbose_name="所属回复", null=True, blank=True)
file = models.FileField(upload_to='community/media/', verbose_name="文件")
media_type = models.CharField(max_length=10, choices=MEDIA_TYPE_CHOICES, default='image', verbose_name="媒体类型")
created_at = models.DateTimeField(auto_now_add=True, verbose_name="上传时间")
def __str__(self):
return f"{self.media_type} - {self.file.name}"
class Meta:
verbose_name = "论坛媒体资源"
verbose_name_plural = "论坛媒体资源管理"