修改过滤和字段
This commit is contained in:
parent
024847575c
commit
38a1a0a808
@ -227,7 +227,7 @@ class CampaignStatusConsumer(WebsocketConsumer):
|
||||
"followers": f"{int(creator.followers / 1000)}k" if creator.followers else "0",
|
||||
"gmv_generated": f"${creator.gmv}k" if creator.gmv else "$0",
|
||||
"views_generated": f"{int(creator.avg_video_views / 1000)}k" if creator.avg_video_views else "0",
|
||||
"pricing": f"${creator.pricing_min}" if creator.pricing_min else "$0",
|
||||
"pricing": f"${creator.pricing}" if creator.pricing else "$0",
|
||||
"status": status
|
||||
}
|
||||
creator_list.append(creator_data)
|
||||
|
@ -151,7 +151,7 @@ class OfferStatusService:
|
||||
"followers": followers_formatted,
|
||||
"gmv_generated": f"${creator.gmv}k" if creator.gmv else "$0",
|
||||
"views_generated": avg_views_formatted,
|
||||
"pricing": f"${creator.pricing_min}" if creator.pricing_min else "$0",
|
||||
"pricing": f"${creator.pricing}" if creator.pricing else "$0",
|
||||
"status": status
|
||||
}
|
||||
creator_list.append(creator_data)
|
||||
|
@ -365,7 +365,7 @@ class CampaignViewSet(viewsets.ModelViewSet):
|
||||
"followers": f"{int(creator.followers / 1000)}k" if creator.followers else "0",
|
||||
"GMV Generated": f"${creator.gmv}k" if creator.gmv else "$0",
|
||||
"Views Generated": f"{int(creator.avg_video_views / 1000)}k" if creator.avg_video_views else "0",
|
||||
"Pricing": f"${creator.pricing_min}" if creator.pricing_min else "$0",
|
||||
"Pricing": f"${creator.pricing}" if creator.pricing else "$0",
|
||||
"Status": cc.status
|
||||
}
|
||||
all_creator_list.append(creator_data)
|
||||
@ -521,7 +521,7 @@ class CampaignViewSet(viewsets.ModelViewSet):
|
||||
"followers": f"{int(creator.followers / 1000)}k" if creator.followers else "0",
|
||||
"gmv_generated": f"${creator.gmv}k" if creator.gmv else "$0",
|
||||
"views_generated": f"{int(creator.avg_video_views / 1000)}k" if creator.avg_video_views else "0",
|
||||
"pricing": f"${creator.pricing_min}" if creator.pricing_min else "$0",
|
||||
"pricing": f"${creator.pricing}" if creator.pricing else "$0",
|
||||
"status": status
|
||||
}
|
||||
creator_list.append(creator_data)
|
||||
@ -589,7 +589,7 @@ class CampaignViewSet(viewsets.ModelViewSet):
|
||||
"followers": f"{int(creator.followers / 1000)}k" if creator.followers else "0",
|
||||
"gmv_generated": f"${creator.gmv}k" if creator.gmv else "$0",
|
||||
"views_generated": f"{int(creator.avg_video_views / 1000)}k" if creator.avg_video_views else "0",
|
||||
"pricing": f"${creator.pricing_min}" if creator.pricing_min else "$0",
|
||||
"pricing": f"${creator.pricing}" if creator.pricing else "$0",
|
||||
"status": status
|
||||
}
|
||||
creator_list.append(creator_data)
|
||||
@ -648,7 +648,7 @@ class CampaignViewSet(viewsets.ModelViewSet):
|
||||
"followers": f"{int(creator.followers / 1000)}k" if creator.followers else "0",
|
||||
"gmv_generated": f"${creator.gmv}k" if creator.gmv else "$0",
|
||||
"views_generated": f"{int(creator.avg_video_views / 1000)}k" if creator.avg_video_views else "0",
|
||||
"pricing": f"${creator.pricing_min}" if creator.pricing_min else "$0",
|
||||
"pricing": f"${creator.pricing}" if creator.pricing else "$0",
|
||||
"status": status
|
||||
}
|
||||
creator_list.append(creator_data)
|
||||
|
@ -1,365 +0,0 @@
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.utils import timezone
|
||||
from apps.daren_detail.models import (
|
||||
CollaborationMetrics, VideoMetrics, LiveMetrics, CreatorProfile,
|
||||
CreatorCampaign, BrandCampaign, CreatorVideo, FollowerMetrics,
|
||||
TrendMetrics, PublicCreatorPool, PrivateCreatorPool, PrivateCreatorRelation
|
||||
)
|
||||
from apps.expertproducts.models import Product as ExpertProduct, Creator as ExpertCreator, Negotiation, Message
|
||||
from apps.discovery.models import SearchSession, Creator as DiscoveryCreator
|
||||
from apps.brands.models import Brand, Product as BrandProduct, Campaign, BrandChatSession
|
||||
from apps.template.models import TemplateCategory, Template
|
||||
from apps.user.models import User
|
||||
import random
|
||||
from datetime import datetime, timedelta
|
||||
import uuid
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = '填充测试数据到所有相关模型'
|
||||
|
||||
def handle(self, *args, **kwargs):
|
||||
self.stdout.write('开始填充数据...')
|
||||
|
||||
# 创建用户(避免重复)
|
||||
user, created = User.objects.get_or_create(
|
||||
email='test@example.com',
|
||||
defaults={
|
||||
'password': 'testpassword',
|
||||
'company': '测试公司',
|
||||
'name': '测试用户',
|
||||
'is_first_login': False,
|
||||
'last_login': timezone.now()
|
||||
}
|
||||
)
|
||||
|
||||
# 创建品牌(避免重复)
|
||||
brands = []
|
||||
brand_names = ['U品牌', 'R品牌', 'X品牌', 'Q品牌', 'A品牌', 'M品牌']
|
||||
for name in brand_names:
|
||||
brand, _ = Brand.objects.get_or_create(
|
||||
name=name,
|
||||
defaults={
|
||||
'description': f'{name}的描述信息',
|
||||
'logo_url': f'https://example.com/logos/{name}.png',
|
||||
'category': '电子产品',
|
||||
'source': '内部',
|
||||
'collab_count': random.randint(5, 20),
|
||||
'creators_count': random.randint(10, 50),
|
||||
'campaign_id': str(uuid.uuid4()),
|
||||
'total_gmv_achieved': random.randint(10000, 100000),
|
||||
'total_views_achieved': random.randint(100000, 1000000),
|
||||
'shop_overall_rating': round(random.uniform(3.5, 5.0), 1),
|
||||
'dataset_id_list': [str(uuid.uuid4()) for _ in range(3)]
|
||||
}
|
||||
)
|
||||
brands.append(brand)
|
||||
|
||||
# 创建品牌产品(避免重复)
|
||||
products = []
|
||||
for brand in brands:
|
||||
for i in range(3):
|
||||
product, _ = BrandProduct.objects.get_or_create(
|
||||
brand=brand,
|
||||
name=f'{brand.name}产品{i+1}',
|
||||
defaults={
|
||||
'description': f'{brand.name}产品{i+1}的详细描述',
|
||||
'image_url': f'https://example.com/products/{brand.name}_{i+1}.jpg',
|
||||
'pid': f'PID_{uuid.uuid4().hex[:8]}',
|
||||
'commission_rate': random.uniform(5, 20),
|
||||
'open_collab': random.uniform(10, 30),
|
||||
'available_samples': random.randint(10, 100),
|
||||
'sales_price_min': random.uniform(100, 500),
|
||||
'sales_price_max': random.uniform(500, 2000),
|
||||
'stock': random.randint(100, 1000),
|
||||
'items_sold': random.randint(50, 500),
|
||||
'product_rating': round(random.uniform(3.5, 5.0), 1),
|
||||
'reviews_count': random.randint(10, 100),
|
||||
'collab_creators': random.randint(5, 20),
|
||||
'tiktok_shop': random.choice([True, False]),
|
||||
'dataset_id': str(uuid.uuid4())
|
||||
}
|
||||
)
|
||||
products.append(product)
|
||||
|
||||
# 创建活动(避免重复)
|
||||
campaigns = []
|
||||
for brand in brands:
|
||||
campaign, _ = Campaign.objects.get_or_create(
|
||||
brand=brand,
|
||||
name=f'{brand.name}活动',
|
||||
defaults={
|
||||
'description': f'{brand.name}的活动描述',
|
||||
'image_url': f'https://example.com/campaigns/{brand.name}.jpg',
|
||||
'service': '直播带货',
|
||||
'creator_type': 'KOL',
|
||||
'creator_level': 'L3',
|
||||
'creator_category': '电子产品',
|
||||
'creators_count': random.randint(5, 20),
|
||||
'gmv': '10000-50000',
|
||||
'followers': '10000-100000',
|
||||
'views': '100000-1000000',
|
||||
'budget': '5000-20000',
|
||||
'start_date': timezone.now(),
|
||||
'end_date': timezone.now() + timedelta(days=30),
|
||||
'dataset_id': str(uuid.uuid4()),
|
||||
'status': 'in_progress',
|
||||
'gmv_achieved': '25000',
|
||||
'views_achieved': '500000',
|
||||
'video_link': 'https://example.com/videos/campaign.mp4'
|
||||
}
|
||||
)
|
||||
campaign.link_product.set(random.sample(products, 2))
|
||||
campaigns.append(campaign)
|
||||
|
||||
# 创建创作者档案
|
||||
creators = []
|
||||
for i in range(10):
|
||||
creator = CreatorProfile.objects.create(
|
||||
name=f'创作者{i+1}',
|
||||
avatar_url=f'https://example.com/avatars/creator_{i+1}.jpg',
|
||||
email=f'creator{i+1}@example.com',
|
||||
instagram=f'creator{i+1}',
|
||||
tiktok_link=f'https://tiktok.com/@{i+1}',
|
||||
location='上海',
|
||||
live_schedule='每周一、三、五 20:00-22:00',
|
||||
category=random.choice([c[0] for c in CreatorProfile.CATEGORY_CHOICES]),
|
||||
e_commerce_level=random.randint(1, 7),
|
||||
exposure_level=random.choice([e[0] for e in CreatorProfile.EXPOSURE_LEVEL_CHOICES]),
|
||||
followers=random.randint(10000, 1000000),
|
||||
gmv=random.uniform(10000, 1000000),
|
||||
items_sold=random.uniform(1000, 10000),
|
||||
avg_video_views=random.randint(10000, 100000),
|
||||
pricing_min=random.uniform(1000, 5000),
|
||||
pricing_max=random.uniform(5000, 20000),
|
||||
pricing_package='基础套餐',
|
||||
collab_count=random.randint(5, 50),
|
||||
latest_collab='最新合作项目',
|
||||
e_commerce_platforms=['TikTok', 'Instagram'],
|
||||
gmv_by_channel={'TikTok': 60, 'Instagram': 40},
|
||||
gmv_by_category={'电子产品': 70, '服装': 30},
|
||||
mcn='知名MCN机构'
|
||||
)
|
||||
creators.append(creator)
|
||||
|
||||
# 创建协作指标
|
||||
for creator in creators:
|
||||
CollaborationMetrics.objects.create(
|
||||
avg_commission_rate=random.uniform(5, 20),
|
||||
products_count=random.randint(10, 50),
|
||||
brand_collaborations=random.randint(5, 20),
|
||||
min_product_price=random.uniform(100, 500),
|
||||
max_product_price=random.uniform(500, 2000),
|
||||
start_date=timezone.now().date(),
|
||||
end_date=timezone.now().date() + timedelta(days=30),
|
||||
creator=creator
|
||||
)
|
||||
|
||||
# 创建视频指标
|
||||
for creator in creators:
|
||||
for video_type in ['regular', 'shoppable']:
|
||||
VideoMetrics.objects.create(
|
||||
video_type=video_type,
|
||||
gpm=random.uniform(100, 1000),
|
||||
videos_count=random.randint(10, 50),
|
||||
avg_views=random.uniform(10000, 100000),
|
||||
avg_engagement=random.uniform(1, 10),
|
||||
avg_likes=random.randint(1000, 10000),
|
||||
start_date=timezone.now().date(),
|
||||
end_date=timezone.now().date() + timedelta(days=30),
|
||||
creator=creator
|
||||
)
|
||||
|
||||
# 创建直播指标
|
||||
for creator in creators:
|
||||
for live_type in ['regular', 'shoppable']:
|
||||
LiveMetrics.objects.create(
|
||||
live_type=live_type,
|
||||
gpm=random.uniform(100, 1000),
|
||||
lives_count=random.randint(5, 20),
|
||||
avg_views=random.uniform(10000, 100000),
|
||||
avg_engagement=random.uniform(1, 10),
|
||||
avg_likes=random.randint(1000, 10000),
|
||||
start_date=timezone.now().date(),
|
||||
end_date=timezone.now().date() + timedelta(days=30),
|
||||
creator=creator
|
||||
)
|
||||
|
||||
# 创建创作者视频
|
||||
for creator in creators:
|
||||
for i in range(3):
|
||||
CreatorVideo.objects.create(
|
||||
creator=creator,
|
||||
title=f'视频标题{i+1}',
|
||||
description=f'视频描述{i+1}',
|
||||
thumbnail_url=f'https://example.com/thumbnails/video_{i+1}.jpg',
|
||||
video_url=f'https://example.com/videos/video_{i+1}.mp4',
|
||||
video_id=f'VID_{uuid.uuid4().hex[:8]}',
|
||||
video_type=random.choice(['regular', 'product']),
|
||||
badge=random.choice(['red', 'gold']),
|
||||
view_count=random.randint(10000, 100000),
|
||||
like_count=random.randint(1000, 10000),
|
||||
comment_count=random.randint(100, 1000),
|
||||
has_product=random.choice([True, False]),
|
||||
product_name=f'产品{i+1}' if random.choice([True, False]) else None,
|
||||
product_url=f'https://example.com/products/{i+1}' if random.choice([True, False]) else None,
|
||||
release_date=timezone.now().date()
|
||||
)
|
||||
|
||||
# 创建粉丝指标
|
||||
for creator in creators:
|
||||
FollowerMetrics.objects.create(
|
||||
creator=creator,
|
||||
start_date=timezone.now().date(),
|
||||
end_date=timezone.now().date() + timedelta(days=30),
|
||||
female_percentage=random.uniform(40, 60),
|
||||
male_percentage=random.uniform(40, 60),
|
||||
age_18_24_percentage=random.uniform(20, 40),
|
||||
age_25_34_percentage=random.uniform(30, 50),
|
||||
age_35_44_percentage=random.uniform(10, 30),
|
||||
age_45_54_percentage=random.uniform(5, 15),
|
||||
age_55_plus_percentage=random.uniform(1, 10),
|
||||
location_data={
|
||||
'上海': random.uniform(10, 30),
|
||||
'北京': random.uniform(10, 30),
|
||||
'广州': random.uniform(5, 20),
|
||||
'深圳': random.uniform(5, 20),
|
||||
'杭州': random.uniform(5, 15)
|
||||
}
|
||||
)
|
||||
|
||||
# 创建趋势指标
|
||||
for creator in creators:
|
||||
for i in range(10):
|
||||
TrendMetrics.objects.create(
|
||||
creator=creator,
|
||||
date=timezone.now().date() - timedelta(days=i),
|
||||
gmv=random.uniform(1000, 10000),
|
||||
items_sold=random.randint(100, 1000),
|
||||
followers_count=random.randint(10000, 100000),
|
||||
video_views=random.randint(10000, 100000),
|
||||
engagement_rate=random.uniform(1, 10)
|
||||
)
|
||||
|
||||
# 创建公有达人库
|
||||
for creator in creators:
|
||||
PublicCreatorPool.objects.create(
|
||||
creator=creator,
|
||||
category=creator.category,
|
||||
remark=f'备注信息:{creator.name}的详细信息'
|
||||
)
|
||||
|
||||
# 创建私有达人库(避免重复)
|
||||
private_pool, _ = PrivateCreatorPool.objects.get_or_create(
|
||||
user=user,
|
||||
name='我的收藏',
|
||||
defaults={
|
||||
'description': '收藏的达人列表',
|
||||
'is_default': True
|
||||
}
|
||||
)
|
||||
|
||||
# 创建私有达人关联
|
||||
for creator in random.sample(creators, 5):
|
||||
PrivateCreatorRelation.objects.create(
|
||||
private_pool=private_pool,
|
||||
creator=creator,
|
||||
added_from_public=True,
|
||||
notes=f'关于{creator.name}的笔记',
|
||||
status=random.choice(['active', 'archived', 'favorite'])
|
||||
)
|
||||
|
||||
# 创建专家产品
|
||||
expert_products = []
|
||||
for i in range(10):
|
||||
p = ExpertProduct.objects.create(
|
||||
name=f'专家产品{i+1}',
|
||||
category='电子产品',
|
||||
max_price=random.uniform(1000, 5000),
|
||||
min_price=random.uniform(500, 1000),
|
||||
description=f'专家产品{i+1}的详细描述'
|
||||
)
|
||||
expert_products.append(p)
|
||||
|
||||
# 创建专家创作者
|
||||
expert_creators = []
|
||||
for i in range(10):
|
||||
c = ExpertCreator.objects.create(
|
||||
name=f'专家创作者{i+1}',
|
||||
sex=random.choice(['男', '女']),
|
||||
age=random.randint(18, 45),
|
||||
category='带货类',
|
||||
followers=random.randint(10000, 1000000)
|
||||
)
|
||||
expert_creators.append(c)
|
||||
|
||||
# 创建谈判记录
|
||||
for i in range(10):
|
||||
negotiation = Negotiation.objects.create(
|
||||
creator=expert_creators[i],
|
||||
product=expert_products[i],
|
||||
status=random.choice(['brand_review', 'price_negotiation', 'contract_review']),
|
||||
current_round=random.randint(1, 5),
|
||||
context={'current_price': random.uniform(500, 2000)}
|
||||
)
|
||||
|
||||
# 为每个谈判创建消息
|
||||
for j in range(3):
|
||||
Message.objects.create(
|
||||
negotiation=negotiation,
|
||||
role=random.choice(['user', 'assistant']),
|
||||
content=f'谈判消息{j+1}',
|
||||
stage=negotiation.status
|
||||
)
|
||||
|
||||
# 创建搜索会话
|
||||
for i in range(10):
|
||||
session = SearchSession.objects.create(
|
||||
session_number=i+1,
|
||||
creator_count=random.randint(5, 20),
|
||||
shoppable_creators=random.randint(2, 10),
|
||||
avg_followers=random.uniform(10000, 100000),
|
||||
avg_gmv=random.uniform(10000, 100000),
|
||||
avg_video_views=random.uniform(10000, 100000)
|
||||
)
|
||||
|
||||
# 为每个会话创建创作者
|
||||
for j in range(5):
|
||||
DiscoveryCreator.objects.create(
|
||||
session=session,
|
||||
name=f'发现创作者{j+1}',
|
||||
avatar=f'https://example.com/avatars/discovery_{j+1}.jpg',
|
||||
category=random.choice([c[0] for c in DiscoveryCreator.CATEGORIES]),
|
||||
ecommerce_level=random.choice([l[0] for l in DiscoveryCreator.ECOMMERCE_LEVELS]),
|
||||
exposure_level=random.choice([l[0] for l in DiscoveryCreator.EXPOSURE_LEVELS]),
|
||||
followers=random.uniform(10000, 1000000),
|
||||
gmv=random.uniform(10000, 100000),
|
||||
items_sold=random.uniform(1000, 10000),
|
||||
avg_video_views=random.uniform(10000, 100000),
|
||||
has_ecommerce=random.choice([True, False]),
|
||||
tiktok_url=f'https://tiktok.com/@{j+1}'
|
||||
)
|
||||
|
||||
# 创建模板分类
|
||||
categories = []
|
||||
for i in range(5):
|
||||
category = TemplateCategory.objects.create(
|
||||
name=f'模板分类{i+1}',
|
||||
description=f'模板分类{i+1}的描述'
|
||||
)
|
||||
categories.append(category)
|
||||
|
||||
# 创建模板
|
||||
for category in categories:
|
||||
for i in range(2):
|
||||
Template.objects.create(
|
||||
title=f'模板{i+1}',
|
||||
content=f'这是模板{i+1}的详细内容,包含了很多有用的信息。',
|
||||
category=category,
|
||||
mission=random.choice([m[0] for m in Template.MISSION_CHOICES]),
|
||||
platform=random.choice([p[0] for p in Template.PLATFORM_CHOICES]),
|
||||
collaboration_type=random.choice([c[0] for c in Template.COLLABORATION_CHOICES]),
|
||||
service=random.choice([s[0] for s in Template.SERVICE_CHOICES]),
|
||||
is_public=random.choice([True, False])
|
||||
)
|
||||
|
||||
self.stdout.write(self.style.SUCCESS('数据填充完成!'))
|
@ -0,0 +1,26 @@
|
||||
# Generated by Django 5.1.5 on 2025-05-23 03:48
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('daren_detail', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='creatorprofile',
|
||||
name='pricing_max',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='creatorprofile',
|
||||
name='pricing_min',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='creatorprofile',
|
||||
name='pricing',
|
||||
field=models.DecimalField(blank=True, decimal_places=2, max_digits=10, null=True, verbose_name='个人定价'),
|
||||
),
|
||||
]
|
@ -190,8 +190,7 @@ class CreatorProfile(models.Model):
|
||||
avg_video_views = models.IntegerField(default=0, blank=True, null=True, verbose_name="平均视频浏览量")
|
||||
|
||||
# 价格信息 - Pricing
|
||||
pricing_min = models.DecimalField(max_digits=10, decimal_places=2, blank=True, null=True, verbose_name="最低个人定价")
|
||||
pricing_max = models.DecimalField(max_digits=10, decimal_places=2, blank=True, null=True, verbose_name="最高个人定价")
|
||||
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
|
||||
|
@ -59,6 +59,7 @@ urlpatterns = [
|
||||
|
||||
# 公有达人和私有达人API
|
||||
path('public/creators/', views.get_public_creators, name='get_public_creators'),
|
||||
path('public/creators/filter/', views.filter_public_creators, name='filter_public_creators'),
|
||||
path('public/creators/add/', views.add_to_public_pool, name='add_to_public_pool'),
|
||||
|
||||
# 私有达人库
|
||||
@ -69,4 +70,5 @@ urlpatterns = [
|
||||
path('private/pools/creators/add/', views.add_creator_to_private_pool, name='add_creator_to_private_pool'),
|
||||
path('private/pools/creators/update/', views.update_creator_in_private_pool, name='update_creator_in_private_pool'),
|
||||
path('private/pools/creators/remove/', views.remove_creator_from_private_pool, name='remove_creator_from_private_pool'),
|
||||
path('private/pools/creators/filter/', views.filter_private_pool_creators, name='filter_private_pool_creators'),
|
||||
]
|
||||
|
@ -135,7 +135,8 @@ def filter_creators(request):
|
||||
min_price, max_price = pricing_val.split('-')
|
||||
min_price = float(min_price)
|
||||
max_price = float(max_price)
|
||||
query = query.filter(pricing_min__gte=min_price, pricing_max__lte=max_price)
|
||||
# 修改:根据单一定价字段判断是否在区间内
|
||||
query = query.filter(pricing__gte=min_price, pricing__lte=max_price)
|
||||
|
||||
# 获取总数据量
|
||||
total_count = query.count()
|
||||
@ -159,11 +160,8 @@ def filter_creators(request):
|
||||
followers_formatted = f"{int(creator.followers / 1000)}k" if creator.followers else "0"
|
||||
avg_views_formatted = f"{int(creator.avg_video_views / 1000)}k" if creator.avg_video_views else "0"
|
||||
|
||||
# 格式化价格区间
|
||||
if creator.pricing_min is not None and creator.pricing_max is not None:
|
||||
pricing_range = f"${creator.pricing_min}-{creator.pricing_max}"
|
||||
else:
|
||||
pricing_range = None
|
||||
# 格式化价格
|
||||
pricing_formatted = f"${creator.pricing}" if creator.pricing else None
|
||||
|
||||
# 格式化结果
|
||||
formatted_creator = {
|
||||
@ -178,10 +176,8 @@ def filter_creators(request):
|
||||
"GMV": gmv_formatted,
|
||||
"Items Sold": f"{creator.items_sold}k" if creator.items_sold else None,
|
||||
"Avg. Video Views": avg_views_formatted,
|
||||
"Pricing": {
|
||||
"Range": pricing_range,
|
||||
"Pack. P": creator.pricing_package
|
||||
},
|
||||
"Pricing": pricing_formatted,
|
||||
"Pricing Package": creator.pricing_package,
|
||||
"# Collab": creator.collab_count,
|
||||
"Latest Collab.": creator.latest_collab,
|
||||
"E-commerce": creator.e_commerce_platforms,
|
||||
@ -285,10 +281,17 @@ def add_creator(request):
|
||||
creator.avg_video_views = avg_video_views
|
||||
|
||||
# 更新价格信息
|
||||
pricing = data.get('pricing', {})
|
||||
if pricing:
|
||||
creator.pricing_individual = pricing.get('individual', creator.pricing_individual)
|
||||
creator.pricing_package = pricing.get('package', creator.pricing_package)
|
||||
pricing_data = data.get('pricing', {})
|
||||
if pricing_data:
|
||||
# 处理individual价格或直接的pricing值
|
||||
if 'individual' in pricing_data:
|
||||
creator.pricing = pricing_data.get('individual')
|
||||
elif 'pricing' in pricing_data:
|
||||
creator.pricing = pricing_data.get('pricing')
|
||||
elif isinstance(pricing_data, (int, float)):
|
||||
creator.pricing = pricing_data
|
||||
|
||||
creator.pricing_package = pricing_data.get('package', creator.pricing_package) if isinstance(pricing_data, dict) else creator.pricing_package
|
||||
|
||||
creator.collab_count = data.get('collab_count', creator.collab_count)
|
||||
creator.latest_collab = data.get('latest_collab', creator.latest_collab)
|
||||
@ -508,9 +511,9 @@ def get_creator_detail(request, creator_id):
|
||||
gmv_per_customer = 0
|
||||
|
||||
if creator.avg_video_views and creator.avg_video_views > 0:
|
||||
if creator.pricing_min:
|
||||
if creator.pricing:
|
||||
try:
|
||||
price = float(creator.pricing_min)
|
||||
price = float(creator.pricing)
|
||||
gpm = (price * 1000) / creator.avg_video_views
|
||||
gpm = round(gpm, 2)
|
||||
except (ValueError, AttributeError):
|
||||
@ -554,7 +557,7 @@ def get_creator_detail(request, creator_id):
|
||||
creator.category] if creator.category else [],
|
||||
"mcn": creator.mcn or "",
|
||||
"pricing": {
|
||||
"range": f"${creator.pricing_min}-{creator.pricing_max}" if creator.pricing_min is not None and creator.pricing_max is not None else None,
|
||||
"price": f"${creator.pricing}" if creator.pricing else None,
|
||||
"package": creator.pricing_package
|
||||
},
|
||||
"collab_count": creator.collab_count,
|
||||
@ -2017,7 +2020,7 @@ def get_public_creators(request):
|
||||
category = request.GET.get('category')
|
||||
keyword = request.GET.get('keyword')
|
||||
|
||||
# 基础查询
|
||||
# 基础查询 - 从公有达人池开始
|
||||
public_creators = PublicCreatorPool.objects.all()
|
||||
|
||||
# 应用过滤条件
|
||||
@ -2055,11 +2058,8 @@ def get_public_creators(request):
|
||||
followers_formatted = f"{int(creator.followers / 1000)}k" if creator.followers else "0"
|
||||
avg_views_formatted = f"{int(creator.avg_video_views / 1000)}k" if creator.avg_video_views else "0"
|
||||
|
||||
# 格式化价格区间
|
||||
if creator.pricing_min is not None and creator.pricing_max is not None:
|
||||
pricing_range = f"${creator.pricing_min}-{creator.pricing_max}"
|
||||
else:
|
||||
pricing_range = None
|
||||
# 格式化价格
|
||||
pricing_formatted = f"${creator.pricing}" if creator.pricing else None
|
||||
|
||||
# 格式化结果
|
||||
formatted_creator = {
|
||||
@ -2073,7 +2073,8 @@ def get_public_creators(request):
|
||||
"followers": followers_formatted,
|
||||
"gmv": gmv_formatted,
|
||||
"avg_video_views": avg_views_formatted,
|
||||
"pricing": pricing_range,
|
||||
"pricing": pricing_formatted,
|
||||
"pricing_package": creator.pricing_package,
|
||||
"collab_count": creator.collab_count,
|
||||
"remark": public_creator.remark,
|
||||
"category_public": public_creator.category
|
||||
@ -2370,12 +2371,12 @@ def get_private_pool_creators(request, pool_id=None):
|
||||
# 检查pool_id是否提供
|
||||
if not pool_id:
|
||||
pool_id = request.GET.get('pool_id')
|
||||
if not pool_id:
|
||||
return JsonResponse({
|
||||
'code': 400,
|
||||
'message': '缺少必要参数: pool_id',
|
||||
'data': None
|
||||
}, json_dumps_params={'ensure_ascii': False})
|
||||
if not pool_id:
|
||||
return JsonResponse({
|
||||
'code': 400,
|
||||
'message': '缺少必要参数: pool_id',
|
||||
'data': None
|
||||
}, json_dumps_params={'ensure_ascii': False})
|
||||
|
||||
# 获取分页参数
|
||||
page = int(request.GET.get('page', 1))
|
||||
@ -2438,8 +2439,8 @@ def get_private_pool_creators(request, pool_id=None):
|
||||
avg_views_formatted = f"{int(creator.avg_video_views / 1000)}k" if creator.avg_video_views else "0"
|
||||
|
||||
# 格式化价格区间
|
||||
if creator.pricing_min is not None and creator.pricing_max is not None:
|
||||
pricing_range = f"${creator.pricing_min}-{creator.pricing_max}"
|
||||
if creator.pricing is not None:
|
||||
pricing_range = f"${creator.pricing}"
|
||||
else:
|
||||
pricing_range = None
|
||||
|
||||
@ -2766,6 +2767,439 @@ def remove_creator_from_private_pool(request):
|
||||
}, json_dumps_params={'ensure_ascii': False})
|
||||
|
||||
|
||||
@api_view(['POST'])
|
||||
@authentication_classes([CustomTokenAuthentication])
|
||||
@csrf_exempt
|
||||
@require_http_methods(["POST"])
|
||||
def filter_public_creators(request):
|
||||
"""根据过滤条件筛选公有达人库列表"""
|
||||
try:
|
||||
from .models import PublicCreatorPool, CreatorProfile
|
||||
import json
|
||||
from django.db.models import Q
|
||||
|
||||
# 从URL获取分页参数
|
||||
page = int(request.GET.get('page', 1))
|
||||
page_size = int(request.GET.get('page_size', 10))
|
||||
|
||||
# 解析POST请求体
|
||||
data = json.loads(request.body)
|
||||
filter_data = data.get('filter', {})
|
||||
|
||||
# 基础查询 - 从公有达人池开始
|
||||
public_creators = PublicCreatorPool.objects.all()
|
||||
|
||||
# 达人分类过滤(Category 多选过滤)
|
||||
category = filter_data.get('category')
|
||||
if category and len(category) > 0:
|
||||
public_creators = public_creators.filter(creator__category__in=category)
|
||||
|
||||
# 电商能力等级过滤 (L1-L7),多选
|
||||
e_commerce_level = filter_data.get('e_commerce_level')
|
||||
if e_commerce_level and len(e_commerce_level) > 0:
|
||||
level_nums = []
|
||||
for level_str in e_commerce_level:
|
||||
if level_str.startswith('L'):
|
||||
level_nums.append(int(level_str[1:]))
|
||||
if level_nums:
|
||||
public_creators = public_creators.filter(creator__e_commerce_level__in=level_nums)
|
||||
|
||||
# 曝光等级过滤 (KOL-1, KOL-2, KOC-1等),多选
|
||||
exposure_level = filter_data.get('exposure_level')
|
||||
if exposure_level and len(exposure_level) > 0:
|
||||
public_creators = public_creators.filter(creator__exposure_level__in=exposure_level)
|
||||
|
||||
# GMV范围过滤 ($0-$5k, $5k-$25k, $25k-$50k等),多选
|
||||
gmv_range = filter_data.get('gmv_range')
|
||||
if gmv_range and len(gmv_range) > 0:
|
||||
gmv_q = Q()
|
||||
for gmv_val in gmv_range:
|
||||
gmv_min, gmv_max = 0, float('inf')
|
||||
if gmv_val == "$0-$5k":
|
||||
gmv_min, gmv_max = 0, 5
|
||||
elif gmv_val == "$5k-$25k":
|
||||
gmv_min, gmv_max = 5, 25
|
||||
elif gmv_val == "$25k-$50k":
|
||||
gmv_min, gmv_max = 25, 50
|
||||
elif gmv_val == "$50k-$150k":
|
||||
gmv_min, gmv_max = 50, 150
|
||||
elif gmv_val == "$150k-$400k":
|
||||
gmv_min, gmv_max = 150, 400
|
||||
elif gmv_val == "$400k-$1500k":
|
||||
gmv_min, gmv_max = 400, 1500
|
||||
elif gmv_val == "$1500k+":
|
||||
gmv_min, gmv_max = 1500, float('inf')
|
||||
|
||||
range_q = Q()
|
||||
if gmv_min > 0:
|
||||
range_q &= Q(creator__gmv__gte=gmv_min)
|
||||
if gmv_max < float('inf'):
|
||||
range_q &= Q(creator__gmv__lte=gmv_max)
|
||||
gmv_q |= range_q
|
||||
|
||||
public_creators = public_creators.filter(gmv_q)
|
||||
|
||||
# 观看量范围过滤,单选
|
||||
views_range = filter_data.get('views_range')
|
||||
if views_range and len(views_range) > 0:
|
||||
views_min, views_max = 0, float('inf')
|
||||
views_val = views_range[0]
|
||||
if views_val == "0-100":
|
||||
views_min, views_max = 0, 100
|
||||
elif views_val == "1k-10k":
|
||||
views_min, views_max = 1000, 10000
|
||||
elif views_val == "10k-100k":
|
||||
views_min, views_max = 10000, 100000
|
||||
elif views_val == "100k-250k":
|
||||
views_min, views_max = 100000, 250000
|
||||
elif views_val == "250k-500k":
|
||||
views_min, views_max = 250000, 500000
|
||||
elif views_val == "500k+":
|
||||
views_min = 500000
|
||||
|
||||
if views_min > 0:
|
||||
public_creators = public_creators.filter(creator__avg_video_views__gte=views_min)
|
||||
if views_max < float('inf'):
|
||||
public_creators = public_creators.filter(creator__avg_video_views__lte=views_max)
|
||||
|
||||
# 价格区间过滤逻辑,单选
|
||||
pricing = filter_data.get('pricing')
|
||||
if pricing and len(pricing) > 0:
|
||||
pricing_val = pricing[0]
|
||||
if '-' in pricing_val:
|
||||
min_price, max_price = pricing_val.split('-')
|
||||
min_price = float(min_price)
|
||||
max_price = float(max_price)
|
||||
# 修改:根据单一定价字段判断是否在区间内
|
||||
public_creators = public_creators.filter(
|
||||
creator__pricing__gte=min_price,
|
||||
creator__pricing__lte=max_price
|
||||
)
|
||||
|
||||
# 获取总数据量
|
||||
total_count = public_creators.count()
|
||||
|
||||
# 计算分页
|
||||
start = (page - 1) * page_size
|
||||
end = start + page_size
|
||||
|
||||
# 执行查询并分页
|
||||
creators = public_creators[start:end]
|
||||
|
||||
creator_list = []
|
||||
for public_creator in creators:
|
||||
creator = public_creator.creator
|
||||
|
||||
# 格式化电商等级
|
||||
e_commerce_level_formatted = f"L{creator.e_commerce_level}" if creator.e_commerce_level else None
|
||||
|
||||
# 格式化GMV
|
||||
gmv_formatted = f"${creator.gmv}k" if creator.gmv else "$0"
|
||||
|
||||
# 格式化粉丝数和观看量
|
||||
followers_formatted = f"{int(creator.followers / 1000)}k" if creator.followers else "0"
|
||||
avg_views_formatted = f"{int(creator.avg_video_views / 1000)}k" if creator.avg_video_views else "0"
|
||||
|
||||
# 格式化价格区间
|
||||
if creator.pricing is not None:
|
||||
pricing_range = f"${creator.pricing}"
|
||||
else:
|
||||
pricing_range = None
|
||||
|
||||
# 格式化结果
|
||||
formatted_creator = {
|
||||
"public_id": public_creator.id,
|
||||
"creator_id": creator.id,
|
||||
"name": creator.name,
|
||||
"avatar": creator.avatar_url,
|
||||
"category": creator.category,
|
||||
"e_commerce_level": e_commerce_level_formatted,
|
||||
"exposure_level": creator.exposure_level,
|
||||
"followers": followers_formatted,
|
||||
"gmv": gmv_formatted,
|
||||
"avg_video_views": avg_views_formatted,
|
||||
"pricing": pricing_range,
|
||||
"pricing_package": creator.pricing_package,
|
||||
"collab_count": creator.collab_count,
|
||||
"remark": public_creator.remark,
|
||||
"category_public": public_creator.category
|
||||
}
|
||||
creator_list.append(formatted_creator)
|
||||
|
||||
# 计算总页数
|
||||
total_pages = (total_count + page_size - 1) // page_size
|
||||
|
||||
# 构造分页信息
|
||||
pagination = {
|
||||
"current_page": page,
|
||||
"total_pages": total_pages,
|
||||
"total_count": total_count,
|
||||
"has_next": page < total_pages,
|
||||
"has_prev": page > 1
|
||||
}
|
||||
|
||||
return JsonResponse({
|
||||
'code': 200,
|
||||
'message': '获取成功',
|
||||
'data': creator_list,
|
||||
'pagination': pagination
|
||||
}, json_dumps_params={'ensure_ascii': False})
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"筛选公有达人库列表失败: {e}")
|
||||
import traceback
|
||||
logger.error(f"详细错误: {traceback.format_exc()}")
|
||||
return JsonResponse({
|
||||
'code': 500,
|
||||
'message': f'筛选公有达人库列表失败: {str(e)}',
|
||||
'data': None
|
||||
}, json_dumps_params={'ensure_ascii': False})
|
||||
|
||||
|
||||
@api_view(['POST'])
|
||||
@authentication_classes([CustomTokenAuthentication])
|
||||
@csrf_exempt
|
||||
@require_http_methods(["POST"])
|
||||
def filter_private_pool_creators(request):
|
||||
"""根据过滤条件筛选私有达人库中的达人"""
|
||||
try:
|
||||
from .models import PrivateCreatorPool, PrivateCreatorRelation
|
||||
import json
|
||||
from django.db.models import Q
|
||||
|
||||
# 解析POST请求体
|
||||
data = json.loads(request.body)
|
||||
|
||||
# 获取私有库ID
|
||||
pool_id = data.get('pool_id')
|
||||
if not pool_id:
|
||||
return JsonResponse({
|
||||
'code': 400,
|
||||
'message': '缺少必要参数: pool_id',
|
||||
'data': None
|
||||
}, json_dumps_params={'ensure_ascii': False})
|
||||
|
||||
# 获取过滤条件
|
||||
filter_data = data.get('filter', {})
|
||||
|
||||
# 获取分页参数
|
||||
page = int(request.GET.get('page', 1))
|
||||
page_size = int(request.GET.get('page_size', 10))
|
||||
|
||||
# 获取状态过滤参数,如果提供了才使用
|
||||
status = filter_data.get('status')
|
||||
|
||||
# 查询私有库信息
|
||||
try:
|
||||
private_pool = PrivateCreatorPool.objects.get(id=pool_id)
|
||||
|
||||
# 检查私有库是否属于当前登录用户
|
||||
if private_pool.user_id != request.user.id:
|
||||
return JsonResponse({
|
||||
'code': 403,
|
||||
'message': '没有权限访问此私有达人库',
|
||||
'data': None
|
||||
}, json_dumps_params={'ensure_ascii': False})
|
||||
|
||||
except PrivateCreatorPool.DoesNotExist:
|
||||
return JsonResponse({
|
||||
'code': 404,
|
||||
'message': f'找不到ID为 {pool_id} 的私有库',
|
||||
'data': None
|
||||
}, json_dumps_params={'ensure_ascii': False})
|
||||
|
||||
# 查询私有库中的达人关联
|
||||
creator_relations = PrivateCreatorRelation.objects.filter(
|
||||
private_pool=private_pool
|
||||
).select_related('creator')
|
||||
|
||||
# 应用状态过滤条件(仅当提供了status参数时)
|
||||
if status:
|
||||
creator_relations = creator_relations.filter(status=status)
|
||||
|
||||
# 应用复杂过滤条件
|
||||
# --------- 从filter_creators借鉴的过滤逻辑 ---------
|
||||
|
||||
# Category 多选过滤
|
||||
category = filter_data.get('category')
|
||||
if category and len(category) > 0:
|
||||
creator_relations = creator_relations.filter(creator__category__in=category)
|
||||
|
||||
# 电商能力等级过滤 (L1-L7),多选
|
||||
e_commerce_level = filter_data.get('e_commerce_level')
|
||||
if e_commerce_level and len(e_commerce_level) > 0:
|
||||
level_nums = []
|
||||
for level_str in e_commerce_level:
|
||||
if level_str.startswith('L'):
|
||||
level_nums.append(int(level_str[1:]))
|
||||
if level_nums:
|
||||
creator_relations = creator_relations.filter(creator__e_commerce_level__in=level_nums)
|
||||
|
||||
# 曝光等级过滤 (KOL-1, KOL-2, KOC-1等),多选
|
||||
exposure_level = filter_data.get('exposure_level')
|
||||
if exposure_level and len(exposure_level) > 0:
|
||||
creator_relations = creator_relations.filter(creator__exposure_level__in=exposure_level)
|
||||
|
||||
# GMV范围过滤 ($0-$5k, $5k-$25k, $25k-$50k等),多选
|
||||
gmv_range = filter_data.get('gmv_range')
|
||||
if gmv_range and len(gmv_range) > 0:
|
||||
gmv_q = Q()
|
||||
for gmv_val in gmv_range:
|
||||
gmv_min, gmv_max = 0, float('inf')
|
||||
if gmv_val == "$0-$5k":
|
||||
gmv_min, gmv_max = 0, 5
|
||||
elif gmv_val == "$5k-$25k":
|
||||
gmv_min, gmv_max = 5, 25
|
||||
elif gmv_val == "$25k-$50k":
|
||||
gmv_min, gmv_max = 25, 50
|
||||
elif gmv_val == "$50k-$150k":
|
||||
gmv_min, gmv_max = 50, 150
|
||||
elif gmv_val == "$150k-$400k":
|
||||
gmv_min, gmv_max = 150, 400
|
||||
elif gmv_val == "$400k-$1500k":
|
||||
gmv_min, gmv_max = 400, 1500
|
||||
elif gmv_val == "$1500k+":
|
||||
gmv_min, gmv_max = 1500, float('inf')
|
||||
|
||||
range_q = Q()
|
||||
if gmv_min > 0:
|
||||
range_q &= Q(creator__gmv__gte=gmv_min)
|
||||
if gmv_max < float('inf'):
|
||||
range_q &= Q(creator__gmv__lte=gmv_max)
|
||||
gmv_q |= range_q
|
||||
|
||||
creator_relations = creator_relations.filter(gmv_q)
|
||||
|
||||
# 观看量范围过滤,单选
|
||||
views_range = filter_data.get('views_range')
|
||||
if views_range and len(views_range) > 0:
|
||||
views_min, views_max = 0, float('inf')
|
||||
views_val = views_range[0]
|
||||
if views_val == "0-100":
|
||||
views_min, views_max = 0, 100
|
||||
elif views_val == "1k-10k":
|
||||
views_min, views_max = 1000, 10000
|
||||
elif views_val == "10k-100k":
|
||||
views_min, views_max = 10000, 100000
|
||||
elif views_val == "100k-250k":
|
||||
views_min, views_max = 100000, 250000
|
||||
elif views_val == "250k-500k":
|
||||
views_min, views_max = 250000, 500000
|
||||
elif views_val == "500k+":
|
||||
views_min = 500000
|
||||
|
||||
if views_min > 0:
|
||||
creator_relations = creator_relations.filter(creator__avg_video_views__gte=views_min)
|
||||
if views_max < float('inf'):
|
||||
creator_relations = creator_relations.filter(creator__avg_video_views__lte=views_max)
|
||||
|
||||
# 价格区间过滤逻辑,单选
|
||||
pricing = filter_data.get('pricing')
|
||||
if pricing and len(pricing) > 0:
|
||||
pricing_val = pricing[0]
|
||||
if '-' in pricing_val:
|
||||
min_price, max_price = pricing_val.split('-')
|
||||
min_price = float(min_price)
|
||||
max_price = float(max_price)
|
||||
# 修改:根据单一定价字段判断是否在区间内
|
||||
creator_relations = creator_relations.filter(
|
||||
creator__pricing__gte=min_price,
|
||||
creator__pricing__lte=max_price
|
||||
)
|
||||
|
||||
# 获取总数据量
|
||||
total_count = creator_relations.count()
|
||||
|
||||
# 计算分页
|
||||
start = (page - 1) * page_size
|
||||
end = start + page_size
|
||||
|
||||
# 执行查询并分页
|
||||
paged_relations = creator_relations[start:end]
|
||||
|
||||
creator_list = []
|
||||
for relation in paged_relations:
|
||||
creator = relation.creator
|
||||
|
||||
# 格式化电商等级
|
||||
e_commerce_level_formatted = f"L{creator.e_commerce_level}" if creator.e_commerce_level else None
|
||||
|
||||
# 格式化GMV
|
||||
gmv_formatted = f"${creator.gmv}k" if creator.gmv else "$0"
|
||||
|
||||
# 格式化粉丝数和观看量
|
||||
followers_formatted = f"{int(creator.followers / 1000)}k" if creator.followers else "0"
|
||||
avg_views_formatted = f"{int(creator.avg_video_views / 1000)}k" if creator.avg_video_views else "0"
|
||||
|
||||
# 格式化价格区间
|
||||
if creator.pricing is not None:
|
||||
pricing_range = f"${creator.pricing}"
|
||||
else:
|
||||
pricing_range = None
|
||||
|
||||
# 格式化结果
|
||||
formatted_creator = {
|
||||
"relation_id": relation.id,
|
||||
"creator_id": creator.id,
|
||||
"name": creator.name,
|
||||
"avatar": creator.avatar_url,
|
||||
"category": creator.category,
|
||||
"e_commerce_level": e_commerce_level_formatted,
|
||||
"exposure_level": creator.exposure_level,
|
||||
"followers": followers_formatted,
|
||||
"gmv": gmv_formatted,
|
||||
"avg_video_views": avg_views_formatted,
|
||||
"pricing": pricing_range, # 使用格式化后的价格区间
|
||||
"pricing_package": creator.pricing_package,
|
||||
"collab_count": creator.collab_count,
|
||||
"notes": relation.notes,
|
||||
"status": relation.status,
|
||||
"added_from_public": relation.added_from_public,
|
||||
"added_at": relation.created_at.strftime('%Y-%m-%d')
|
||||
}
|
||||
creator_list.append(formatted_creator)
|
||||
|
||||
# 计算总页数
|
||||
total_pages = (total_count + page_size - 1) // page_size
|
||||
|
||||
# 构造分页信息
|
||||
pagination = {
|
||||
"current_page": page,
|
||||
"total_pages": total_pages,
|
||||
"total_count": total_count,
|
||||
"has_next": page < total_pages,
|
||||
"has_prev": page > 1
|
||||
}
|
||||
|
||||
# 构造私有库信息
|
||||
pool_info = {
|
||||
"id": private_pool.id,
|
||||
"name": private_pool.name,
|
||||
"description": private_pool.description,
|
||||
"is_default": private_pool.is_default,
|
||||
"user_id": private_pool.user_id,
|
||||
"created_at": private_pool.created_at.strftime('%Y-%m-%d')
|
||||
}
|
||||
|
||||
return JsonResponse({
|
||||
'code': 200,
|
||||
'message': '获取成功',
|
||||
'data': creator_list,
|
||||
'pagination': pagination,
|
||||
'pool_info': pool_info
|
||||
}, json_dumps_params={'ensure_ascii': False})
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"筛选私有达人库列表失败: {e}")
|
||||
import traceback
|
||||
logger.error(f"详细错误: {traceback.format_exc()}")
|
||||
return JsonResponse({
|
||||
'code': 500,
|
||||
'message': f'筛选私有达人库列表失败: {str(e)}',
|
||||
'data': None
|
||||
}, json_dumps_params={'ensure_ascii': False})
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -3,6 +3,14 @@ from rest_framework import exceptions
|
||||
from django.contrib.auth.models import AnonymousUser
|
||||
from .models import User, UserToken
|
||||
from django.utils import timezone
|
||||
from rest_framework.exceptions import APIException
|
||||
from rest_framework import status
|
||||
|
||||
class CustomAuthenticationFailed(APIException):
|
||||
status_code = status.HTTP_401_UNAUTHORIZED
|
||||
|
||||
def __init__(self, code, message):
|
||||
self.detail = {"code": code, "message": message}
|
||||
|
||||
class CustomTokenAuthentication(authentication.BaseAuthentication):
|
||||
keyword = 'Token' # 设置认证头关键字
|
||||
@ -12,14 +20,14 @@ class CustomTokenAuthentication(authentication.BaseAuthentication):
|
||||
auth_header = request.META.get('HTTP_AUTHORIZATION')
|
||||
|
||||
if not auth_header:
|
||||
raise exceptions.AuthenticationFailed('未提供认证头')
|
||||
raise CustomAuthenticationFailed(401, '未提供认证头')
|
||||
|
||||
try:
|
||||
# 提取token
|
||||
parts = auth_header.split()
|
||||
|
||||
if len(parts) != 2 or parts[0] != self.keyword:
|
||||
raise exceptions.AuthenticationFailed('认证头格式不正确')
|
||||
raise CustomAuthenticationFailed(401, '认证头格式不正确')
|
||||
|
||||
token = parts[1]
|
||||
|
||||
@ -30,18 +38,18 @@ class CustomTokenAuthentication(authentication.BaseAuthentication):
|
||||
expired_at__gt=timezone.now() # 确保token未过期
|
||||
)
|
||||
except UserToken.DoesNotExist:
|
||||
raise exceptions.AuthenticationFailed('无效或过期的token')
|
||||
raise CustomAuthenticationFailed(401, '无效或过期的token')
|
||||
|
||||
# 检查用户是否激活
|
||||
if not token_obj.user.is_active:
|
||||
raise exceptions.AuthenticationFailed('用户未激活')
|
||||
raise CustomAuthenticationFailed(401, '用户未激活')
|
||||
|
||||
return (token_obj.user, None)
|
||||
|
||||
except Exception as e:
|
||||
if isinstance(e, exceptions.AuthenticationFailed):
|
||||
if isinstance(e, CustomAuthenticationFailed):
|
||||
raise e
|
||||
raise exceptions.AuthenticationFailed('认证失败')
|
||||
raise CustomAuthenticationFailed(401, '认证失败')
|
||||
|
||||
def authenticate_header(self, request):
|
||||
return self.keyword
|
Loading…
Reference in New Issue
Block a user