2025-06-03 16:10:11 +08:00
|
|
|
|
from django.db import models
|
2025-06-05 18:41:52 +08:00
|
|
|
|
import uuid
|
|
|
|
|
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 Brand(models.Model):
|
|
|
|
|
"""品牌模型"""
|
|
|
|
|
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
|
|
|
|
|
name = models.CharField(max_length=100, unique=True, verbose_name='品牌名称')
|
|
|
|
|
description = models.TextField(blank=True, null=True, verbose_name='品牌描述')
|
|
|
|
|
logo_url = models.CharField(max_length=255, blank=True, null=True, verbose_name='品牌Logo')
|
|
|
|
|
category = models.CharField(max_length=100, blank=True, null=True, verbose_name='品牌分类')
|
|
|
|
|
source = models.CharField(max_length=100, blank=True, null=True, verbose_name='来源')
|
|
|
|
|
collab_count = models.IntegerField(default=0, verbose_name='合作数量')
|
|
|
|
|
creators_count = models.IntegerField(default=0, verbose_name='创作者数量')
|
|
|
|
|
campaign_id = models.CharField(max_length=100, blank=True, null=True, verbose_name='活动ID')
|
|
|
|
|
|
|
|
|
|
# 添加数据统计字段
|
|
|
|
|
total_gmv_achieved = models.DecimalField(max_digits=12, decimal_places=2, default=0, verbose_name='总GMV')
|
|
|
|
|
total_views_achieved = models.DecimalField(max_digits=12, decimal_places=2, default=0, verbose_name='总浏览量')
|
|
|
|
|
shop_overall_rating = models.DecimalField(max_digits=3, decimal_places=1, default=0.0, verbose_name='店铺评分')
|
|
|
|
|
|
|
|
|
|
# 存储关联到此品牌的所有产品和活动知识库ID列表
|
|
|
|
|
dataset_id_list = models.JSONField(default=list, blank=True, verbose_name='知识库ID列表',
|
|
|
|
|
help_text='所有关联的知识库ID列表')
|
|
|
|
|
created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
|
|
|
|
|
updated_at = models.DateTimeField(auto_now=True, verbose_name='更新时间')
|
|
|
|
|
is_active = models.BooleanField(default=True, verbose_name='是否激活')
|
|
|
|
|
|
|
|
|
|
class Meta:
|
|
|
|
|
verbose_name = '品牌'
|
|
|
|
|
verbose_name_plural = '品牌'
|
|
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
|
return self.name
|
|
|
|
|
|
|
|
|
|
class Product(models.Model):
|
|
|
|
|
"""产品模型 - 作为一个知识库"""
|
|
|
|
|
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
|
|
|
|
|
brand = models.ForeignKey(Brand, on_delete=models.CASCADE, related_name='products', verbose_name='所属品牌')
|
|
|
|
|
name = models.CharField(max_length=100, verbose_name='产品名称')
|
|
|
|
|
description = models.TextField(blank=True, null=True, verbose_name='产品描述')
|
|
|
|
|
image_url = models.CharField(max_length=255, blank=True, null=True, verbose_name='产品图片')
|
|
|
|
|
|
|
|
|
|
# 添加产品详情字段
|
|
|
|
|
pid = models.CharField(max_length=100, blank=True, null=True, verbose_name='产品ID')
|
|
|
|
|
commission_rate = models.DecimalField(max_digits=5, decimal_places=2, default=0, verbose_name='佣金率')
|
|
|
|
|
open_collab = models.DecimalField(max_digits=5, decimal_places=2, default=0, verbose_name='开放合作率')
|
|
|
|
|
available_samples = models.IntegerField(default=0, verbose_name='可用样品数')
|
|
|
|
|
sales_price_min = models.DecimalField(max_digits=10, decimal_places=2, default=0, verbose_name='最低销售价')
|
|
|
|
|
sales_price_max = models.DecimalField(max_digits=10, decimal_places=2, default=0, verbose_name='最高销售价')
|
|
|
|
|
stock = models.IntegerField(default=0, verbose_name='库存')
|
|
|
|
|
items_sold = models.IntegerField(default=0, verbose_name='已售数量')
|
|
|
|
|
product_rating = models.DecimalField(max_digits=3, decimal_places=1, default=0, verbose_name='产品评分')
|
|
|
|
|
reviews_count = models.IntegerField(default=0, verbose_name='评价数量')
|
|
|
|
|
collab_creators = models.IntegerField(default=0, verbose_name='合作创作者数')
|
|
|
|
|
tiktok_shop = models.BooleanField(default=False, verbose_name='是否TikTok商店')
|
|
|
|
|
|
|
|
|
|
dataset_id = models.CharField(max_length=100, blank=True, null=True, verbose_name='知识库ID',
|
|
|
|
|
help_text='外部知识库系统中的ID')
|
|
|
|
|
external_id = models.CharField(max_length=100, blank=True, null=True, verbose_name='外部ID',
|
|
|
|
|
help_text='外部系统中的唯一标识')
|
|
|
|
|
created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
|
|
|
|
|
updated_at = models.DateTimeField(auto_now=True, verbose_name='更新时间')
|
|
|
|
|
is_active = models.BooleanField(default=True, verbose_name='是否激活')
|
|
|
|
|
|
|
|
|
|
creators = models.ManyToManyField(
|
|
|
|
|
'CreatorProfile',
|
|
|
|
|
through='CreatorProductMatch',
|
|
|
|
|
related_name='matched_products',
|
|
|
|
|
verbose_name='匹配达人'
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
class Meta:
|
|
|
|
|
verbose_name = '产品'
|
|
|
|
|
verbose_name_plural = '产品'
|
|
|
|
|
unique_together = ['brand', 'name']
|
|
|
|
|
indexes = [
|
|
|
|
|
models.Index(fields=['brand']),
|
|
|
|
|
models.Index(fields=['dataset_id']),
|
|
|
|
|
models.Index(fields=['is_active']),
|
|
|
|
|
models.Index(fields=['pid']),
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
|
return f"{self.brand.name} - {self.name}"
|
|
|
|
|
|
|
|
|
|
def save(self, *args, **kwargs):
|
|
|
|
|
"""重写save方法,更新品牌的dataset_id_list"""
|
|
|
|
|
is_new = self.pk is None
|
|
|
|
|
super().save(*args, **kwargs)
|
|
|
|
|
|
|
|
|
|
# 刷新品牌的dataset_id_list
|
|
|
|
|
if is_new and self.is_active and self.dataset_id:
|
|
|
|
|
brand = self.brand
|
|
|
|
|
if self.dataset_id not in brand.dataset_id_list:
|
|
|
|
|
brand.dataset_id_list.append(self.dataset_id)
|
|
|
|
|
brand.save(update_fields=['dataset_id_list', 'updated_at'])
|
|
|
|
|
|
|
|
|
|
class CreatorProductMatch(models.Model):
|
|
|
|
|
creator = models.ForeignKey('CreatorProfile', on_delete=models.CASCADE, verbose_name='达人')
|
|
|
|
|
product = models.ForeignKey('Product', on_delete=models.CASCADE, verbose_name='产品')
|
|
|
|
|
is_matched = models.BooleanField(default=False, verbose_name='是否匹配')
|
|
|
|
|
match_score = models.FloatField(blank=True, null=True, verbose_name='匹配度分数')
|
|
|
|
|
|
|
|
|
|
class Meta:
|
|
|
|
|
unique_together = ('creator', 'product')
|
|
|
|
|
verbose_name = '达人-产品匹配'
|
|
|
|
|
verbose_name_plural = verbose_name
|
|
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
|
return f"{self.creator} - {self.product} 匹配: {self.is_matched} 分数: {self.match_score}"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-06-03 16:10:11 +08:00
|
|
|
|
|
|
|
|
|
class Dataset(models.Model):
|
|
|
|
|
# 自增主键字段,Django 默认为每个模型提供一个 id 字段
|
|
|
|
|
# 但是如果你需要自定义主键字段,可以用 `primary_key=True` 显式声明
|
|
|
|
|
id = models.AutoField(primary_key=True) # 自增主键
|
|
|
|
|
|
|
|
|
|
# 数据集名称,最长255个字符,不能为空
|
|
|
|
|
name = models.CharField(max_length=255)
|
|
|
|
|
|
|
|
|
|
# 创建该数据集的用户,最长100个字符,不能为空
|
|
|
|
|
user = models.CharField(max_length=100)
|
|
|
|
|
|
|
|
|
|
# 任务类型,最长50个字符,不能为空
|
|
|
|
|
task_type = models.CharField(max_length=16)
|
|
|
|
|
|
|
|
|
|
# 数据集大小,使用BigIntegerField来表示较大的整数
|
|
|
|
|
size = models.CharField(max_length=64)
|
|
|
|
|
|
|
|
|
|
# 数据集的总图片数
|
|
|
|
|
number = models.IntegerField()
|
|
|
|
|
|
|
|
|
|
#数据集的描述
|
|
|
|
|
description = models.TextField(default="")
|
|
|
|
|
|
|
|
|
|
# 创建时间,默认为当前时间戳
|
|
|
|
|
create_time = models.DateTimeField(auto_now_add=True) # 自动设置为当前时间(只在创建时)
|
|
|
|
|
|
|
|
|
|
# 数据集的类别,使用 JSONField 存储类别信息
|
|
|
|
|
categories = models.JSONField(default=list) # 默认值为一个空列表
|
|
|
|
|
|
|
|
|
|
# 该数据集是否上传至minio的一个标识
|
|
|
|
|
is_upload = models.BooleanField(default=False) # 表示数据集是否已上传,默认为 False
|
|
|
|
|
|
|
|
|
|
def update_is_upload(self, upload_status):
|
|
|
|
|
"""更新数据集的上传状态"""
|
|
|
|
|
self.is_upload = upload_status
|
|
|
|
|
self.save() # 保存更改到数据库
|
|
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
|
return self.name # 返回数据集名称作为对象的字符串表示
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Project(models.Model):
|
|
|
|
|
id = models.AutoField(primary_key=True)
|
|
|
|
|
name = models.CharField(max_length=255)
|
|
|
|
|
user = models.CharField(max_length=100)
|
|
|
|
|
task_type = models.CharField(max_length=16)
|
|
|
|
|
description = models.TextField(default="")
|
|
|
|
|
create_time = models.DateTimeField(auto_now_add=True)
|
|
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
|
return self.name
|