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="达人名称") # 修改为支持本地图片上传,同时保持URL兼容性 avatar = models.ImageField(upload_to='avatars/', blank=True, null=True, verbose_name="头像图片") avatar_url = models.TextField(blank=True, null=True, verbose_name="头像URL") platform_id = models.CharField(max_length=255, blank=True, null=True, verbose_name="Platform ID") # 新增联系方式 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账号") 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="直播时间表") # 新增达人平台字段 PROFILE_CHOICES = [ ('tiktok', 'TikTok'), ('instagram', 'Instagram'), ('youtube', 'YouTube'), ('other', '其他平台'), ] profile = models.CharField(max_length=20, choices=PROFILE_CHOICES, default='tiktok', verbose_name="达人平台") # 新增hashtag和trend字段 hashtags = models.TextField(blank=True, null=True, verbose_name="标签", help_text="以#分隔的标签,例如:#fashion#beauty#lifestyle") trends = models.TextField(blank=True, null=True, verbose_name="趋势", help_text="创作者相关的趋势关键词") # 新增地区字段 region = models.CharField(max_length=100, blank=True, null=True, verbose_name="地区") # 新增主页链接字段 tiktok_link = models.URLField(max_length=500, blank=True, null=True, verbose_name="主页链接") # 新增对标美区达人等级 us_creator_level = models.CharField(max_length=50, blank=True, null=True, verbose_name="对标美区达人等级") # 新增报价字段 price_gbp = models.DecimalField(max_digits=10, decimal_places=2, blank=True, null=True, verbose_name="报价(英镑)") price_usd = models.DecimalField(max_digits=10, decimal_places=2, blank=True, null=True, verbose_name="报价(美金)") # 新增GMV(英镑)字段 gmv_gbp = models.DecimalField(max_digits=12, decimal_places=2, blank=True, null=True, verbose_name="GMV(英镑)") # 新增链接字段 link = models.URLField(max_length=500, 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 pricing = models.DecimalField(max_digits=10, decimal_places=2, blank=True, null=True, verbose_name="个人定价") 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="更新时间") def get_avatar_url(self): """获取头像URL,优先返回本地图片,其次返回外部URL""" if self.avatar: return self.avatar.url elif self.avatar_url: return self.avatar_url return None 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 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", "已归档"), ("favorite", "收藏"), ("public_removed", "公有库已移除") ]) # 时间戳 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}"