2025-05-19 18:23:59 +08:00
|
|
|
|
from django.db import models
|
|
|
|
|
# from apps.daren_detail.models import User
|
|
|
|
|
|
|
|
|
|
# 修改User模型导入
|
|
|
|
|
from apps.user.models import User
|
|
|
|
|
from apps.brands.models import Campaign as BrandCampaign
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 新增模型:协作指标数据
|
|
|
|
|
class CollaborationMetrics(models.Model):
|
|
|
|
|
"""协作指标数据模型,Collaboration Metrics部分"""
|
|
|
|
|
avg_commission_rate = models.DecimalField(max_digits=5, decimal_places=2, verbose_name="平均佣金率(%)")
|
|
|
|
|
products_count = models.IntegerField(verbose_name="产品数量")
|
|
|
|
|
brand_collaborations = models.IntegerField(verbose_name="品牌合作数量")
|
|
|
|
|
min_product_price = models.DecimalField(max_digits=10, decimal_places=2, verbose_name="最低产品价格($)")
|
|
|
|
|
max_product_price = models.DecimalField(max_digits=10, decimal_places=2, verbose_name="最高产品价格($)")
|
|
|
|
|
|
|
|
|
|
# 时间范围
|
|
|
|
|
start_date = models.DateField(verbose_name="开始日期")
|
|
|
|
|
end_date = models.DateField(verbose_name="结束日期")
|
|
|
|
|
|
|
|
|
|
# 所属创作者
|
|
|
|
|
creator = models.ForeignKey('CreatorProfile', on_delete=models.CASCADE, related_name="collaboration_metrics",
|
|
|
|
|
verbose_name="创作者")
|
|
|
|
|
|
|
|
|
|
# 时间戳
|
|
|
|
|
create_time = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
|
|
|
|
|
update_time = models.DateTimeField(auto_now=True, verbose_name="更新时间")
|
|
|
|
|
|
|
|
|
|
class Meta:
|
|
|
|
|
verbose_name = "协作指标"
|
|
|
|
|
verbose_name_plural = verbose_name
|
|
|
|
|
db_table = "collaboration_metrics"
|
|
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
|
return f"{self.creator.name}的协作指标 ({self.start_date} - {self.end_date})"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 新增模型:视频指标数据
|
|
|
|
|
class VideoMetrics(models.Model):
|
|
|
|
|
"""视频指标数据模型,Video和Shoppable Video部分"""
|
|
|
|
|
video_type = models.CharField(max_length=50, choices=[
|
|
|
|
|
('regular', '普通视频'),
|
|
|
|
|
('shoppable', '可购物视频')
|
|
|
|
|
], default='regular', verbose_name="视频类型")
|
|
|
|
|
|
|
|
|
|
gpm = models.DecimalField(max_digits=10, decimal_places=2, verbose_name="视频GPM($)")
|
|
|
|
|
videos_count = models.IntegerField(verbose_name="视频数量")
|
|
|
|
|
avg_views = models.DecimalField(max_digits=12, decimal_places=2, verbose_name="平均观看量")
|
|
|
|
|
avg_engagement = models.DecimalField(max_digits=5, decimal_places=2, verbose_name="平均互动率(%)")
|
|
|
|
|
avg_likes = models.IntegerField(verbose_name="平均点赞数")
|
|
|
|
|
|
|
|
|
|
# 时间范围
|
|
|
|
|
start_date = models.DateField(verbose_name="开始日期")
|
|
|
|
|
end_date = models.DateField(verbose_name="结束日期")
|
|
|
|
|
|
|
|
|
|
# 所属创作者
|
|
|
|
|
creator = models.ForeignKey('CreatorProfile', on_delete=models.CASCADE, related_name="video_metrics",
|
|
|
|
|
verbose_name="创作者")
|
|
|
|
|
|
|
|
|
|
# 时间戳
|
|
|
|
|
create_time = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
|
|
|
|
|
update_time = models.DateTimeField(auto_now=True, verbose_name="更新时间")
|
|
|
|
|
|
|
|
|
|
class Meta:
|
|
|
|
|
verbose_name = "视频指标"
|
|
|
|
|
verbose_name_plural = verbose_name
|
|
|
|
|
db_table = "video_metrics"
|
|
|
|
|
unique_together = ('creator', 'video_type', 'start_date', 'end_date') # 同一创作者同一时间段同一类型只能有一条记录
|
|
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
|
return f"{self.creator.name}的{self.get_video_type_display()}指标 ({self.start_date} - {self.end_date})"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 新增模型:直播指标数据
|
|
|
|
|
class LiveMetrics(models.Model):
|
|
|
|
|
"""直播指标数据模型,LIVE和Shoppable LIVE部分"""
|
|
|
|
|
live_type = models.CharField(max_length=50, choices=[
|
|
|
|
|
('regular', '普通直播'),
|
|
|
|
|
('shoppable', '可购物直播')
|
|
|
|
|
], default='regular', verbose_name="直播类型")
|
|
|
|
|
|
|
|
|
|
gpm = models.DecimalField(max_digits=10, decimal_places=2, verbose_name="直播GPM($)")
|
|
|
|
|
lives_count = models.IntegerField(verbose_name="直播数量")
|
|
|
|
|
avg_views = models.DecimalField(max_digits=12, decimal_places=2, verbose_name="平均观看量")
|
|
|
|
|
avg_engagement = models.DecimalField(max_digits=5, decimal_places=2, verbose_name="平均互动率(%)")
|
|
|
|
|
avg_likes = models.IntegerField(verbose_name="平均点赞数")
|
|
|
|
|
|
|
|
|
|
# 时间范围
|
|
|
|
|
start_date = models.DateField(verbose_name="开始日期")
|
|
|
|
|
end_date = models.DateField(verbose_name="结束日期")
|
|
|
|
|
|
|
|
|
|
# 所属创作者
|
|
|
|
|
creator = models.ForeignKey('CreatorProfile', on_delete=models.CASCADE, related_name="live_metrics",
|
|
|
|
|
verbose_name="创作者")
|
|
|
|
|
|
|
|
|
|
# 时间戳
|
|
|
|
|
create_time = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
|
|
|
|
|
update_time = models.DateTimeField(auto_now=True, verbose_name="更新时间")
|
|
|
|
|
|
|
|
|
|
class Meta:
|
|
|
|
|
verbose_name = "直播指标"
|
|
|
|
|
verbose_name_plural = verbose_name
|
|
|
|
|
db_table = "live_metrics"
|
|
|
|
|
unique_together = ('creator', 'live_type', 'start_date', 'end_date') # 同一创作者同一时间段同一类型只能有一条记录
|
|
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
|
return f"{self.creator.name}的{self.get_live_type_display()}指标 ({self.start_date} - {self.end_date})"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class CreatorProfile(models.Model):
|
|
|
|
|
"""达人信息模型,用于筛选功能"""
|
|
|
|
|
# 基本信息
|
|
|
|
|
name = models.CharField(max_length=255, verbose_name="达人名称")
|
2025-05-23 19:08:40 +08:00
|
|
|
|
# 修改为支持本地图片上传,同时保持URL兼容性
|
|
|
|
|
avatar = models.ImageField(upload_to='avatars/', blank=True, null=True, verbose_name="头像图片")
|
2025-05-19 18:23:59 +08:00
|
|
|
|
avatar_url = models.TextField(blank=True, null=True, verbose_name="头像URL")
|
|
|
|
|
|
|
|
|
|
# 新增联系方式
|
|
|
|
|
email = models.EmailField(max_length=255, blank=True, null=True, verbose_name="电子邮箱")
|
|
|
|
|
instagram = models.CharField(max_length=255, blank=True, null=True, verbose_name="Instagram账号")
|
|
|
|
|
tiktok_link = models.URLField(max_length=255, blank=True, null=True, verbose_name="TikTok链接")
|
|
|
|
|
location = models.CharField(max_length=100, blank=True, null=True, verbose_name="位置")
|
|
|
|
|
live_schedule = models.CharField(max_length=255, blank=True, null=True, verbose_name="直播时间表")
|
|
|
|
|
|
|
|
|
|
# 类别 - Category
|
|
|
|
|
CATEGORY_CHOICES = [
|
|
|
|
|
('Phones & Electronics', '手机与电子产品'),
|
|
|
|
|
('Homes Supplies', '家居用品'),
|
|
|
|
|
('Kitchenware', '厨房用品'),
|
|
|
|
|
('Textiles & Soft Furnishings', '纺织品和软装'),
|
|
|
|
|
('Household Appliances', '家用电器'),
|
|
|
|
|
('Womenswear & Underwear', '女装和内衣'),
|
|
|
|
|
('Muslim Fashion', '穆斯林时尚'),
|
|
|
|
|
('Shoes', '鞋类'),
|
|
|
|
|
('Beauty & Personal Care', '美容和个人护理'),
|
|
|
|
|
('Computers & Office Equipment', '电脑和办公设备'),
|
|
|
|
|
('Pet Supplies', '宠物用品'),
|
|
|
|
|
('Baby & Maternity', '婴儿和孕妇用品'),
|
|
|
|
|
('Sports & Outdoor', '运动和户外'),
|
|
|
|
|
('Toys', '玩具'),
|
|
|
|
|
('Furniture', '家具'),
|
|
|
|
|
('Tools & Hardware', '工具和硬件'),
|
|
|
|
|
('Home Improvement', '家居装修'),
|
|
|
|
|
('Automotive & Motorcycle', '汽车和摩托车'),
|
|
|
|
|
('Fashion Accessories', '时尚配饰'),
|
|
|
|
|
('Food & Beverages', '食品和饮料'),
|
|
|
|
|
('Health', '健康'),
|
|
|
|
|
('Books, Magazines & Audio', '书籍、杂志和音频'),
|
|
|
|
|
('Kids Fashion', '儿童时尚'),
|
|
|
|
|
('Menswear & Underwear', '男装和内衣'),
|
|
|
|
|
('Luggage & Bags', '行李和包'),
|
|
|
|
|
('Pre-Owned Collections', '二手收藏'),
|
|
|
|
|
('Jewellery Accessories & Derivatives', '珠宝配饰及衍生品'),
|
|
|
|
|
]
|
|
|
|
|
category = models.CharField(max_length=100, choices=CATEGORY_CHOICES, blank=True, null=True, verbose_name="类别")
|
|
|
|
|
|
|
|
|
|
# 电商等级 - E-commerce Level (L1-L7)
|
|
|
|
|
E_COMMERCE_LEVEL_CHOICES = [
|
|
|
|
|
(1, 'L1'),
|
|
|
|
|
(2, 'L2'),
|
|
|
|
|
(3, 'L3'),
|
|
|
|
|
(4, 'L4'),
|
|
|
|
|
(5, 'L5'),
|
|
|
|
|
(6, 'L6'),
|
|
|
|
|
(7, 'L7'),
|
|
|
|
|
]
|
|
|
|
|
e_commerce_level = models.IntegerField(choices=E_COMMERCE_LEVEL_CHOICES, blank=True, null=True,
|
|
|
|
|
verbose_name="电商能力等级")
|
|
|
|
|
|
|
|
|
|
# 曝光等级 - Exposure Level (KOC-1, KOC-2, KOL-1, KOL-2, KOL-3)
|
|
|
|
|
EXPOSURE_LEVEL_CHOICES = [
|
|
|
|
|
('KOC-1', 'KOC-1'),
|
|
|
|
|
('KOC-2', 'KOC-2'),
|
|
|
|
|
('KOL-1', 'KOL-1'),
|
|
|
|
|
('KOL-2', 'KOL-2'),
|
|
|
|
|
('KOL-3', 'KOL-3'),
|
|
|
|
|
]
|
|
|
|
|
exposure_level = models.CharField(max_length=10, choices=EXPOSURE_LEVEL_CHOICES, blank=True, null=True,
|
|
|
|
|
verbose_name="曝光等级")
|
|
|
|
|
|
|
|
|
|
# 粉丝数 - Followers
|
|
|
|
|
followers = models.IntegerField(default=0, verbose_name="粉丝数")
|
|
|
|
|
|
|
|
|
|
# GMV - Gross Merchandise Value (in thousands of dollars)
|
|
|
|
|
gmv = models.DecimalField(max_digits=12, decimal_places=2, blank=True, null=True, verbose_name="GMV(千美元)")
|
|
|
|
|
items_sold = models.DecimalField(max_digits=12, decimal_places=2, blank=True, null=True,
|
|
|
|
|
verbose_name="售出商品数量")
|
|
|
|
|
|
|
|
|
|
# 视频数据 - Video Views
|
|
|
|
|
avg_video_views = models.IntegerField(default=0, blank=True, null=True, verbose_name="平均视频浏览量")
|
|
|
|
|
|
|
|
|
|
# 价格信息 - Pricing
|
2025-05-23 12:11:03 +08:00
|
|
|
|
pricing = models.DecimalField(max_digits=10, decimal_places=2, blank=True, null=True, verbose_name="个人定价")
|
2025-05-19 18:23:59 +08:00
|
|
|
|
pricing_package = models.CharField(max_length=100, blank=True, null=True, verbose_name="套餐定价")
|
|
|
|
|
|
|
|
|
|
# 合作信息 - Collaboration
|
|
|
|
|
collab_count = models.IntegerField(default=0, blank=True, null=True, verbose_name="合作次数")
|
|
|
|
|
latest_collab = models.CharField(max_length=100, blank=True, null=True, verbose_name="最新合作")
|
|
|
|
|
|
|
|
|
|
# 电商平台 - E-commerce platforms (存储为JSON数组,如["SUNLINK", "ARZOPA", "BELIFE"])
|
|
|
|
|
e_commerce_platforms = models.JSONField(blank=True, null=True, verbose_name="电商平台")
|
|
|
|
|
|
|
|
|
|
# 分析数据 - Analytics (JSON格式存储销售渠道和类别分布)
|
|
|
|
|
gmv_by_channel = models.JSONField(blank=True, null=True, verbose_name="GMV按渠道分布")
|
|
|
|
|
gmv_by_category = models.JSONField(blank=True, null=True, verbose_name="GMV按类别分布")
|
|
|
|
|
|
|
|
|
|
# MCN机构
|
|
|
|
|
mcn = models.CharField(max_length=255, blank=True, null=True, verbose_name="MCN机构")
|
|
|
|
|
|
|
|
|
|
# 时间戳
|
|
|
|
|
create_time = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
|
|
|
|
|
update_time = models.DateTimeField(auto_now=True, verbose_name="更新时间")
|
|
|
|
|
|
2025-05-23 19:08:40 +08:00
|
|
|
|
def get_avatar_url(self):
|
|
|
|
|
"""获取头像URL,优先返回本地图片,其次返回外部URL"""
|
|
|
|
|
if self.avatar:
|
|
|
|
|
return self.avatar.url
|
|
|
|
|
elif self.avatar_url:
|
|
|
|
|
return self.avatar_url
|
|
|
|
|
return None
|
|
|
|
|
|
2025-05-19 18:23:59 +08:00
|
|
|
|
class Meta:
|
|
|
|
|
verbose_name = "达人信息"
|
|
|
|
|
verbose_name_plural = verbose_name
|
|
|
|
|
db_table = "creator_profiles"
|
|
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
|
return f"{self.name}"
|
|
|
|
|
|
|
|
|
|
class CreatorCampaign(models.Model):
|
|
|
|
|
"""达人-活动关联模型"""
|
|
|
|
|
creator = models.ForeignKey('CreatorProfile', on_delete=models.CASCADE, verbose_name="达人",
|
|
|
|
|
related_name="campaigns")
|
|
|
|
|
campaign = models.ForeignKey(BrandCampaign, on_delete=models.CASCADE, verbose_name="活动", related_name="creators")
|
|
|
|
|
status = models.CharField(max_length=20, default="pending", verbose_name="状态",
|
|
|
|
|
choices=[
|
|
|
|
|
("pending", "待处理"),
|
|
|
|
|
("accepted", "已接受"),
|
|
|
|
|
("rejected", "已拒绝"),
|
|
|
|
|
("completed", "已完成")
|
|
|
|
|
])
|
|
|
|
|
|
|
|
|
|
# 时间戳
|
|
|
|
|
create_time = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
|
|
|
|
|
update_time = models.DateTimeField(auto_now=True, verbose_name="更新时间")
|
|
|
|
|
|
|
|
|
|
class Meta:
|
|
|
|
|
verbose_name = "达人活动关联"
|
|
|
|
|
verbose_name_plural = verbose_name
|
|
|
|
|
db_table = "creator_campaigns"
|
|
|
|
|
unique_together = ('creator', 'campaign') # 一个达人在一个活动中只能有一条关联记录
|
|
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
|
return f"{self.creator.name} - {self.campaign.name}"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class BrandCampaign(models.Model):
|
|
|
|
|
"""品牌活动数据模型"""
|
|
|
|
|
BRAND_CHOICES = [
|
|
|
|
|
('U', 'U品牌'),
|
|
|
|
|
('R', 'R品牌'),
|
|
|
|
|
('X', 'X品牌'),
|
|
|
|
|
('Q', 'Q品牌'),
|
|
|
|
|
('A', 'A品牌'),
|
|
|
|
|
('M', 'M品牌'),
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
STATUS_CHOICES = [
|
|
|
|
|
('completed', '已完成'),
|
|
|
|
|
('in_progress', '进行中'),
|
|
|
|
|
('rejected', '已拒绝'),
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
brand_id = models.CharField(max_length=10, choices=BRAND_CHOICES, verbose_name="品牌ID")
|
|
|
|
|
brand_name = models.CharField(max_length=255, default="brand", verbose_name="品牌名称")
|
|
|
|
|
brand_color = models.CharField(max_length=20, default="#000000", verbose_name="品牌颜色")
|
|
|
|
|
|
|
|
|
|
# 添加关联到Campaign模型的外键
|
|
|
|
|
campaign = models.ForeignKey(BrandCampaign, on_delete=models.SET_NULL, null=True, blank=True, verbose_name="关联活动",
|
|
|
|
|
related_name="brand_campaigns")
|
|
|
|
|
|
|
|
|
|
pricing_detail = models.CharField(max_length=50, verbose_name="价格详情")
|
|
|
|
|
start_date = models.DateField(verbose_name="开始日期")
|
|
|
|
|
end_date = models.DateField(verbose_name="结束日期")
|
|
|
|
|
|
|
|
|
|
status = models.CharField(max_length=20, choices=STATUS_CHOICES, verbose_name="状态")
|
|
|
|
|
gmv_achieved = models.CharField(max_length=50, verbose_name="实现GMV")
|
|
|
|
|
views_achieved = models.CharField(max_length=50, verbose_name="实现观看量")
|
|
|
|
|
video_link = models.URLField(max_length=255, blank=True, null=True, verbose_name="视频链接")
|
|
|
|
|
|
|
|
|
|
# 时间戳
|
|
|
|
|
create_time = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
|
|
|
|
|
update_time = models.DateTimeField(auto_now=True, verbose_name="更新时间")
|
|
|
|
|
|
|
|
|
|
class Meta:
|
|
|
|
|
verbose_name = "品牌活动数据"
|
|
|
|
|
verbose_name_plural = verbose_name
|
|
|
|
|
db_table = "brand_campaigns"
|
|
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
|
return f"{self.brand_id} - {self.brand_name}"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class CreatorVideo(models.Model):
|
|
|
|
|
"""创作者视频模型,用于存储视频相关信息"""
|
|
|
|
|
# 关联字段
|
|
|
|
|
creator = models.ForeignKey('CreatorProfile', on_delete=models.CASCADE, related_name='videos')
|
|
|
|
|
|
|
|
|
|
# 视频基本信息
|
|
|
|
|
title = models.CharField(max_length=255, verbose_name="视频标题")
|
|
|
|
|
description = models.TextField(blank=True, null=True, verbose_name="视频描述")
|
|
|
|
|
thumbnail_url = models.URLField(max_length=500, blank=True, null=True, verbose_name="缩略图URL")
|
|
|
|
|
video_url = models.URLField(max_length=500, blank=True, null=True, verbose_name="视频URL")
|
|
|
|
|
video_id = models.CharField(max_length=100, verbose_name="视频ID")
|
|
|
|
|
|
|
|
|
|
# 视频类型
|
|
|
|
|
TYPE_CHOICES = [
|
|
|
|
|
('regular', '普通视频'),
|
|
|
|
|
('product', '带产品视频')
|
|
|
|
|
]
|
|
|
|
|
video_type = models.CharField(max_length=20, choices=TYPE_CHOICES, default='regular', verbose_name="视频类型")
|
|
|
|
|
|
|
|
|
|
# 视频标记
|
|
|
|
|
BADGE_CHOICES = [
|
|
|
|
|
('red', '红色标记'),
|
|
|
|
|
('gold', '金色标记')
|
|
|
|
|
]
|
|
|
|
|
badge = models.CharField(max_length=20, choices=BADGE_CHOICES, blank=True, null=True, verbose_name="视频标记")
|
|
|
|
|
|
|
|
|
|
# 视频统计
|
|
|
|
|
view_count = models.IntegerField(default=0, verbose_name="观看次数")
|
|
|
|
|
like_count = models.IntegerField(default=0, verbose_name="点赞数")
|
|
|
|
|
comment_count = models.IntegerField(default=0, verbose_name="评论数")
|
|
|
|
|
|
|
|
|
|
# 产品信息 (仅对带产品视频有效)
|
|
|
|
|
has_product = models.BooleanField(default=False, verbose_name="是否有产品")
|
|
|
|
|
product_name = models.CharField(max_length=255, blank=True, null=True, verbose_name="产品名称")
|
|
|
|
|
product_url = models.URLField(max_length=500, blank=True, null=True, verbose_name="产品链接")
|
|
|
|
|
|
|
|
|
|
# 发布信息
|
|
|
|
|
release_date = models.DateField(verbose_name="发布日期")
|
|
|
|
|
|
|
|
|
|
# 时间戳
|
|
|
|
|
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 = "创作者视频"
|
|
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
|
return f"{self.creator.name} - {self.title}"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class FollowerMetrics(models.Model):
|
|
|
|
|
"""粉丝统计数据模型"""
|
|
|
|
|
# 关联字段
|
|
|
|
|
creator = models.ForeignKey('CreatorProfile', on_delete=models.CASCADE, related_name='follower_metrics')
|
|
|
|
|
|
|
|
|
|
# 时间范围
|
|
|
|
|
start_date = models.DateField()
|
|
|
|
|
end_date = models.DateField()
|
|
|
|
|
|
|
|
|
|
# 粉丝性别统计
|
|
|
|
|
female_percentage = models.FloatField(default=0) # 女性百分比
|
|
|
|
|
male_percentage = models.FloatField(default=0) # 男性百分比
|
|
|
|
|
|
|
|
|
|
# 粉丝年龄分布
|
|
|
|
|
age_18_24_percentage = models.FloatField(default=0) # 18-24岁百分比
|
|
|
|
|
age_25_34_percentage = models.FloatField(default=0) # 25-34岁百分比
|
|
|
|
|
age_35_44_percentage = models.FloatField(default=0) # 35-44岁百分比
|
|
|
|
|
age_45_54_percentage = models.FloatField(default=0) # 45-54岁百分比
|
|
|
|
|
age_55_plus_percentage = models.FloatField(default=0) # 55+岁百分比
|
|
|
|
|
|
|
|
|
|
# 粉丝地域分布 (前5位)
|
|
|
|
|
location_data = models.JSONField(default=dict) # 格式: {"TX": 11, "FL": 8, "NY": 8, "GE": 5.5, "CA": 5}
|
|
|
|
|
|
|
|
|
|
# 创建和更新时间
|
|
|
|
|
created_at = models.DateTimeField(auto_now_add=True)
|
|
|
|
|
updated_at = models.DateTimeField(auto_now=True)
|
|
|
|
|
|
|
|
|
|
class Meta:
|
|
|
|
|
verbose_name = '粉丝统计'
|
|
|
|
|
verbose_name_plural = '粉丝统计'
|
|
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
|
return f"{self.creator.name} 粉丝统计 ({self.start_date} - {self.end_date})"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class TrendMetrics(models.Model):
|
|
|
|
|
"""趋势统计数据模型"""
|
|
|
|
|
# 关联字段
|
|
|
|
|
creator = models.ForeignKey('CreatorProfile', on_delete=models.CASCADE, related_name='trend_metrics')
|
|
|
|
|
|
|
|
|
|
# 时间范围
|
|
|
|
|
date = models.DateField() # 数据日期
|
|
|
|
|
|
|
|
|
|
# 指标数据
|
|
|
|
|
gmv = models.FloatField(default=0) # GMV值
|
|
|
|
|
items_sold = models.IntegerField(default=0) # 销售商品数
|
|
|
|
|
followers_count = models.IntegerField(default=0) # 粉丝数
|
|
|
|
|
video_views = models.IntegerField(default=0) # 视频观看量
|
|
|
|
|
engagement_rate = models.FloatField(default=0) # 互动率(百分比)
|
|
|
|
|
|
|
|
|
|
# 创建和更新时间
|
|
|
|
|
created_at = models.DateTimeField(auto_now_add=True)
|
|
|
|
|
updated_at = models.DateTimeField(auto_now=True)
|
|
|
|
|
|
|
|
|
|
class Meta:
|
|
|
|
|
verbose_name = '趋势指标'
|
|
|
|
|
verbose_name_plural = '趋势指标'
|
|
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
|
return f"{self.creator.name} 趋势指标 ({self.date})"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 公有达人库
|
|
|
|
|
class PublicCreatorPool(models.Model):
|
|
|
|
|
"""公有达人库模型,存储系统提供的公共达人信息"""
|
|
|
|
|
creator = models.ForeignKey(CreatorProfile, on_delete=models.CASCADE, verbose_name="达人",
|
|
|
|
|
related_name="public_pool")
|
|
|
|
|
# is_active = models.BooleanField(default=True, verbose_name="是否活跃")
|
|
|
|
|
category = models.CharField(max_length=255, blank=True, null=True, verbose_name="分类")
|
|
|
|
|
remark = models.TextField(blank=True, null=True, verbose_name="备注")
|
|
|
|
|
|
|
|
|
|
# 时间戳
|
|
|
|
|
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 = verbose_name
|
|
|
|
|
db_table = "public_creator_pool"
|
|
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
|
return f"公有达人: {self.creator.name}"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 私有达人库
|
|
|
|
|
class PrivateCreatorPool(models.Model):
|
|
|
|
|
"""私有达人库模型,用户可以将公有达人添加到自己的私有库中"""
|
|
|
|
|
user = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name="用户", related_name="private_creators", db_column='user_id')
|
|
|
|
|
name = models.CharField(max_length=255, verbose_name="私有库名称")
|
|
|
|
|
description = models.TextField(blank=True, null=True, verbose_name="描述")
|
|
|
|
|
is_default = models.BooleanField(default=False, verbose_name="是否为默认库")
|
|
|
|
|
# is_active = models.BooleanField(default=True, verbose_name="是否活跃")
|
|
|
|
|
|
|
|
|
|
# 时间戳
|
|
|
|
|
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 = verbose_name
|
|
|
|
|
db_table = "private_creator_pool"
|
|
|
|
|
unique_together = ('user', 'name') # 同一用户下不能有同名私有库
|
|
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
|
return f"{self.user.email}的{self.name}"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 私有达人库与达人的关联表
|
|
|
|
|
class PrivateCreatorRelation(models.Model):
|
|
|
|
|
"""私有达人库与达人的关联表,记录哪些达人被添加到了哪个私有库"""
|
|
|
|
|
private_pool = models.ForeignKey(PrivateCreatorPool, on_delete=models.CASCADE, verbose_name="私有达人库",
|
|
|
|
|
related_name="creator_relations")
|
|
|
|
|
creator = models.ForeignKey(CreatorProfile, on_delete=models.CASCADE, verbose_name="达人",
|
|
|
|
|
related_name="private_pool_relations")
|
|
|
|
|
added_from_public = models.BooleanField(default=True, verbose_name="是否从公有库添加")
|
|
|
|
|
notes = models.TextField(blank=True, null=True, verbose_name="笔记")
|
|
|
|
|
status = models.CharField(max_length=20, default="active", verbose_name="状态",
|
|
|
|
|
choices=[
|
|
|
|
|
("active", "活跃"),
|
|
|
|
|
("archived", "已归档"),
|
2025-05-23 19:08:40 +08:00
|
|
|
|
("favorite", "收藏"),
|
|
|
|
|
("public_removed", "公有库已移除")
|
2025-05-19 18:23:59 +08:00
|
|
|
|
])
|
|
|
|
|
|
|
|
|
|
# 时间戳
|
|
|
|
|
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 = verbose_name
|
|
|
|
|
db_table = "private_creator_relations"
|
|
|
|
|
unique_together = ('private_pool', 'creator') # 同一私有库中不能重复添加同一个达人
|
|
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
|
return f"{self.private_pool.name} - {self.creator.name}"
|