Compare commits

..

No commits in common. "83f8dd931e0fc8c7c4825d00472602c12633529b" and "900eb0fa71299ee2cf213788fbdb5e86d313d98b" have entirely different histories.

13 changed files with 332 additions and 551 deletions

View File

@ -1373,6 +1373,7 @@ def get_creator_trends(request, creator_id=None):
(datetime.now().date() - timedelta(days=30 - i)).strftime('%Y-%m-%d')
for i in range(31)
]
# 设定随机的起始值和波动
import random
base_gmv = random.uniform(500, 3000)

View File

@ -1,29 +0,0 @@
# Generated by Django 5.1.5 on 2025-05-20 04:36
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('brands', '0002_alter_campaign_id'),
('daren_detail', '0001_initial'),
('expertproducts', '0001_initial'),
]
operations = [
migrations.AlterField(
model_name='negotiation',
name='creator',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='daren_detail.creatorprofile'),
),
migrations.AlterField(
model_name='negotiation',
name='product',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='brands.product'),
),
migrations.DeleteModel(
name='Creator',
),
]

View File

@ -1,16 +0,0 @@
# Generated by Django 5.1.5 on 2025-05-20 04:37
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('expertproducts', '0002_alter_negotiation_creator_alter_negotiation_product_and_more'),
]
operations = [
migrations.DeleteModel(
name='Product',
),
]

View File

@ -1,12 +1,28 @@
from django.db import models
from django.db.models import JSONField # 用于存储动态谈判条款
from django.utils import timezone # Import timezone for timestamping
from apps.daren_detail.models import CreatorProfile # 导入CreatorProfile模型
from apps.brands.models import Product # 导入Product模型
# Create your models here.
class Product(models.Model):
name = models.CharField(max_length=100) # 商品名称
category = models.CharField(max_length=50) # 商品类目
max_price = models.DecimalField(max_digits=10, decimal_places=2) # 最高价格(公开报价)
min_price = models.DecimalField(max_digits=10, decimal_places=2) # 最低价格(底线)
description = models.TextField(blank=True) # 商品描述(可选)
def __str__(self):
return f"{self.name} ({self.max_price}元)"
class Creator(models.Model):
name = models.CharField(max_length=100) # 达人名称
sex = models.CharField(max_length=10, default='') # 达人性别,设置默认值为未知
age = models.IntegerField(default=18) # 达人年龄设置默认值为18
category = models.CharField(max_length=50) # 达人类别(如带货类)
followers = models.IntegerField() # 粉丝数
class Negotiation(models.Model):
STATUS_CHOICES = [
('brand_review', '品牌回顾'),
@ -18,8 +34,8 @@ class Negotiation(models.Model):
('abandoned', '已放弃'),
]
creator = models.ForeignKey(CreatorProfile, on_delete=models.CASCADE)
product = models.ForeignKey(Product, on_delete=models.CASCADE)
creator = models.ForeignKey('daren_detail.CreatorProfile', on_delete=models.CASCADE)
product = models.ForeignKey('brands.Product', on_delete=models.CASCADE)
status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='price_negotiation')
current_round = models.IntegerField(default=1) # 当前谈判轮次
context = models.JSONField(default=dict) # 存储谈判上下文(如当前报价)

View File

@ -2,9 +2,8 @@ from rest_framework import serializers
# from user_management.models import OperatorAccount, PlatformAccount, Video, KnowledgeBase, KnowledgeBaseDocument
import uuid
from django.db.models import Q
from apps.daren_detail.models import CreatorProfile
from apps.brands.models import Product
from .models import Negotiation, Message
from .models import Product, Creator, Negotiation, Message
#
# class OperatorAccountSerializer(serializers.ModelSerializer):
@ -156,15 +155,16 @@ class ProductSerializer(serializers.ModelSerializer):
fields = '__all__'
class CreatorSerializer(serializers.ModelSerializer):
class Meta:
model = Creator
fields = '__all__'
class NegotiationSerializer(serializers.ModelSerializer):
creator_name = serializers.CharField(source='creator.name', read_only=True)
creator_avatar = serializers.CharField(source='creator.avatar_url', read_only=True)
product_name = serializers.CharField(source='product.name', read_only=True)
product_category = serializers.CharField(source='product.category', read_only=True)
class Meta:
model = Negotiation
fields = ['id', 'creator', 'creator_name', 'creator_avatar', 'product', 'product_name', 'product_category', 'status', 'current_round', 'context']
fields = '__all__'
read_only_fields = ('status', 'current_round')

View File

@ -17,16 +17,15 @@ import subprocess
import re
from django.db import connection
from django.core.mail import EmailMessage
from ollama import Client
from rest_framework.views import APIView
from rest_framework.parsers import MultiPartParser, FormParser
from .models import Product, Negotiation, Message
from .serializers import NegotiationSerializer
from apps.daren_detail.models import CreatorProfile
from apps.brands.models import Product
from .models import Product, Creator, Negotiation, Message
from .serializers import ProductSerializer, CreatorSerializer, NegotiationSerializer
import requests
from ollama import Client
client = Client(host="http://localhost:11434")
class ContentAnalysisAPI(APIView):
parser_classes = (MultiPartParser, FormParser)
@ -173,7 +172,7 @@ class NegotiationViewSet(viewsets.ModelViewSet):
product = serializer.validated_data['product']
# 检查该用户是否存在
if not CreatorProfile.objects.filter(id=creator.id).exists():
if not Creator.objects.filter(id=creator.id).exists():
return Response({
"code": 404,
"message": "未找到指定的达人",
@ -347,7 +346,7 @@ class NegotiationViewSet(viewsets.ModelViewSet):
})
# 获取所有相关的达人
creators = CreatorProfile.objects.filter(negotiation__in=negotiations).distinct()
creators = Creator.objects.filter(negotiation__in=negotiations).distinct()
if creators.exists():
# 序列化达人数据
creator_data = [{'name': creator.name, 'category': creator.category, 'followers': creator.followers} for
@ -363,7 +362,6 @@ class NegotiationViewSet(viewsets.ModelViewSet):
@action(detail=False, methods=['post'])
def offer_status(self, request):
"""获取谈判状态"""
# 获取请求参数
creator_id = request.data.get('creator_id')
product_id = request.data.get('product_id')
@ -376,7 +374,7 @@ class NegotiationViewSet(viewsets.ModelViewSet):
# 查找符合条件的谈判
try:
creator = CreatorProfile.objects.get(id=creator_id)
creator = Creator.objects.get(id=creator_id)
negotiation = Negotiation.objects.get(creator=creator, product_id=product_id)
return Response({
'code': 200,
@ -385,12 +383,6 @@ class NegotiationViewSet(viewsets.ModelViewSet):
'status': negotiation.status
}
})
except CreatorProfile.DoesNotExist:
return Response({
'code': 404,
'message': f'找不到ID为{creator_id}的达人',
'data': None
})
except Negotiation.DoesNotExist:
return Response({
'code': 404,

View File

@ -1,42 +0,0 @@
from rest_framework import authentication
from rest_framework import exceptions
from django.contrib.auth.models import AnonymousUser
from .models import User, UserToken
from django.utils import timezone
class CustomTokenAuthentication(authentication.BaseAuthentication):
keyword = 'Token' # 设置认证头关键字
def authenticate(self, request):
# 从请求头获取token
auth_header = request.META.get('HTTP_AUTHORIZATION')
if not auth_header:
return None
try:
# 提取token
parts = auth_header.split()
if len(parts) != 2 or parts[0] != self.keyword:
raise exceptions.AuthenticationFailed('无效的认证头格式,应为: Token <token>')
token = parts[1]
# 查找token记录并确保token存在且有效
try:
token_obj = UserToken.objects.select_related('user').get(
token=token,
expired_at__gt=timezone.now() # 确保token未过期
)
except UserToken.DoesNotExist:
raise exceptions.AuthenticationFailed('无效的token')
# 检查用户是否激活
if not token_obj.user.is_active:
raise exceptions.AuthenticationFailed('用户已被禁用')
return (token_obj.user, None)
except Exception as e:
raise exceptions.AuthenticationFailed(f'认证失败: {str(e)}')

View File

@ -1,27 +0,0 @@
# Generated by Django 5.1.5 on 2025-05-20 03:49
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('user', '0002_remove_user_is_active'),
]
operations = [
migrations.CreateModel(
name='UserToken',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('token', models.CharField(max_length=40, unique=True)),
('created_at', models.DateTimeField(auto_now_add=True)),
('expired_at', models.DateTimeField()),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='tokens', to='user.user')),
],
options={
'db_table': 'user_token',
},
),
]

View File

@ -1,23 +0,0 @@
# Generated by Django 5.1.5 on 2025-05-20 03:52
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('user', '0003_usertoken'),
]
operations = [
migrations.AddField(
model_name='user',
name='is_active',
field=models.BooleanField(default=True),
),
migrations.AddField(
model_name='user',
name='is_staff',
field=models.BooleanField(default=False),
),
]

View File

@ -1,65 +1,23 @@
from django.db import models
from django.utils import timezone
from datetime import timedelta
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager
class UserManager(BaseUserManager):
def create_user(self, email, password=None, **extra_fields):
if not email:
raise ValueError('邮箱地址不能为空')
email = self.normalize_email(email)
user = self.model(email=email, **extra_fields)
if password:
user.set_password(password)
user.save(using=self._db)
return user
class User(AbstractBaseUser):
"""用户模型,用于登录和账户管理"""
email = models.EmailField(max_length=255, unique=True, verbose_name="电子邮箱")
password = models.CharField(max_length=255, verbose_name="密码")
company = models.CharField(max_length=255, blank=True, null=True, verbose_name="公司名称")
name = models.CharField(max_length=255, blank=True, null=True, verbose_name="用户姓名")
is_first_login = models.BooleanField(default=True, verbose_name="是否首次登录")
last_login = models.DateTimeField(blank=True, null=True, verbose_name="最近登录时间")
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
# 时间戳
created_at = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
updated_at = models.DateTimeField(auto_now=True, verbose_name="更新时间")
objects = UserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
class Meta:
verbose_name = "用户"
verbose_name_plural = verbose_name
db_table = "users"
def __str__(self):
return self.email
@property
def is_authenticated(self):
return True
class UserToken(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='tokens')
token = models.CharField(max_length=40, unique=True)
created_at = models.DateTimeField(auto_now_add=True)
expired_at = models.DateTimeField()
def save(self, *args, **kwargs):
if not self.expired_at:
# 设置token有效期为30天
self.expired_at = timezone.now() + timedelta(days=30)
super().save(*args, **kwargs)
def is_expired(self):
return timezone.now() > self.expired_at
class Meta:
db_table = 'user_token'
from django.db import models
# Create your models here.
class User(models.Model):
"""用户模型,用于登录和账户管理"""
email = models.EmailField(max_length=255, unique=True, verbose_name="电子邮箱")
password = models.CharField(max_length=255, verbose_name="密码")
company = models.CharField(max_length=255, blank=True, null=True, verbose_name="公司名称")
name = models.CharField(max_length=255, blank=True, null=True, verbose_name="用户姓名")
is_first_login = models.BooleanField(default=True, verbose_name="是否首次登录")
last_login = models.DateTimeField(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 = "users"
def __str__(self):
return self.email

View File

@ -1,281 +1,268 @@
from django.http import JsonResponse
# from .models import TiktokUserVideos
import logging
import os
from django.views.decorators.http import require_http_methods
from django.views.decorators.csrf import csrf_exempt
from django.shortcuts import render
import json
import requests
import concurrent.futures
import shutil
import dotenv
import random
from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import IsAuthenticated, AllowAny
import hashlib
import time
from django.contrib.auth.hashers import check_password
from django.utils import timezone
dotenv.load_dotenv()
# 添加logger定义
logger = logging.getLogger(__name__)
directory_monitoring = {}
# 全局变量来控制检测线程
monitor_thread = None
is_monitoring = False
def generate_token(user_id):
"""生成简单的token"""
# 使用用户ID和当前时间戳生成token
token_string = f"{user_id}:{time.time()}"
return hashlib.sha1(token_string.encode()).hexdigest()
def create_user_token(user):
"""创建并保存用户token"""
from .models import UserToken
# 删除该用户的所有旧token
UserToken.objects.filter(user=user).delete()
# 生成新token
token = generate_token(user.id)
# 保存到数据库
user_token = UserToken.objects.create(
user=user,
token=token
)
return token
@csrf_exempt
@api_view(['POST'])
@permission_classes([AllowAny])
def user_login(request):
"""
用户登录接口
返回的 token 使用格式
在请求头中添加
Authorization: Token <your_token>
例如
Authorization: Token fa6931ec4cf5bd46d8dc3a671fe9862c467426b3
"""
try:
from .models import User
import json
from django.contrib.auth.hashers import check_password
from datetime import datetime
data = json.loads(request.body)
# 获取登录参数
email = data.get('email')
password = data.get('password')
if not email or not password:
return JsonResponse({
'code': 400,
'message': '缺少必要参数: email 或 password',
'data': None
}, json_dumps_params={'ensure_ascii': False})
# 查询用户
try:
user = User.objects.get(email=email)
# 验证密码
if not user.check_password(password):
return JsonResponse({
'code': 401,
'message': '用户名或密码错误',
'data': None
}, json_dumps_params={'ensure_ascii': False})
# 生成并保存token
token = create_user_token(user)
# 检查是否首次登录
is_first_login = user.is_first_login
# 更新最后登录时间
user.last_login = timezone.now()
user.save()
# 构造返回数据
user_data = {
'user_id': user.id,
'email': user.email,
'is_first_login': is_first_login,
'name': user.name,
'company': user.company,
'token': token
}
return JsonResponse({
'code': 200,
'message': '登录成功',
'data': user_data
}, json_dumps_params={'ensure_ascii': False})
except User.DoesNotExist:
return JsonResponse({
'code': 404,
'message': '用户不存在',
'data': None
}, 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})
@csrf_exempt
@api_view(['POST'])
@permission_classes([IsAuthenticated])
def update_user_info(request):
"""更新用户信息,需要认证"""
try:
data = json.loads(request.body)
# 获取参数
company = data.get('company')
name = data.get('name')
# 获取当前认证用户
user = request.user
# 如果请求中包含 user_id 且与当前用户不匹配,返回错误
if 'user_id' in data and int(data['user_id']) != user.id:
return JsonResponse({
'code': 403,
'message': '您只能修改自己的信息',
'data': None
}, json_dumps_params={'ensure_ascii': False})
# 如果是首次登录,需要填写公司和姓名
if not company or not name:
return JsonResponse({
'code': 400,
'message': '首次登录需要填写公司和姓名',
'data': None
}, json_dumps_params={'ensure_ascii': False})
# 更新信息
user.company = company
user.name = name
user.is_first_login = False # 更新后不再是首次登录
user.save()
return JsonResponse({
'code': 200,
'message': '信息更新成功',
'data': {
'user_id': user.id,
'email': user.email,
'is_first_login': False,
'name': user.name,
'company': user.company
}
}, 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})
@csrf_exempt
@api_view(['POST'])
@permission_classes([AllowAny])
def user_register(request):
"""用户注册接口"""
try:
from .models import User
import json
from datetime import datetime
data = json.loads(request.body)
# 获取注册参数
email = data.get('email')
password = data.get('password')
company = data.get('company') # 可选参数
name = data.get('name') # 可选参数
# 检查必要参数
if not email or not password:
return JsonResponse({
'code': 400,
'message': '缺少必要参数: email 或 password',
'data': None
}, json_dumps_params={'ensure_ascii': False})
# 检查邮箱是否已注册
if User.objects.filter(email=email).exists():
return JsonResponse({
'code': 409,
'message': '该邮箱已注册',
'data': None
}, json_dumps_params={'ensure_ascii': False})
# 创建用户
try:
# 根据是否提供公司和姓名决定是否为首次登录
is_first_login = not (company and name)
# 创建用户
user = User.objects.create_user(
email=email,
password=password,
company=company,
name=name,
is_first_login=is_first_login,
last_login=timezone.now()
)
# 构造返回数据
user_data = {
'user_id': user.id,
'email': user.email,
'is_first_login': is_first_login,
'company': user.company,
'name': user.name
}
return JsonResponse({
'code': 200,
'message': '注册成功',
'data': user_data
}, json_dumps_params={'ensure_ascii': False})
except Exception as e:
logger.error(f"创建用户失败: {e}")
return JsonResponse({
'code': 500,
'message': f'注册失败: {str(e)}',
'data': None
}, 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})
from django.http import JsonResponse
# from .models import TiktokUserVideos
import logging
import os
from django.views.decorators.http import require_http_methods
from django.views.decorators.csrf import csrf_exempt
from django.shortcuts import render
import json
import requests
import concurrent.futures
import shutil
import dotenv
import random
dotenv.load_dotenv()
# 添加logger定义
logger = logging.getLogger(__name__)
directory_monitoring = {}
# 全局变量来控制检测线程
monitor_thread = None
is_monitoring = False
@csrf_exempt
@require_http_methods(["POST"])
def user_login(request):
"""用户登录接口,首次登录会返回需要填写信息的标志"""
try:
from .models import User
import json
from django.contrib.auth.hashers import check_password, make_password
from datetime import datetime
data = json.loads(request.body)
# 获取登录参数
email = data.get('email')
password = data.get('password')
if not email or not password:
return JsonResponse({
'code': 400,
'message': '缺少必要参数: email 或 password',
'data': None
}, json_dumps_params={'ensure_ascii': False})
# 查询用户
try:
user = User.objects.get(email=email)
# 验证密码
# 注意:这里假设密码已经进行了哈希存储,实际使用时需要采用适当的密码验证方法
# 如果密码未哈希存储,直接比较原始密码
password_valid = (user.password == password)
if not password_valid:
return JsonResponse({
'code': 401,
'message': '用户名或密码错误',
'data': None
}, json_dumps_params={'ensure_ascii': False})
# 检查是否首次登录
is_first_login = user.is_first_login
# 更新最后登录时间
user.last_login = datetime.now()
user.save()
# 构造返回数据
user_data = {
'user_id': user.id,
'email': user.email,
'is_first_login': is_first_login,
'name': user.name,
'company': user.company
}
return JsonResponse({
'code': 200,
'message': '登录成功',
'data': user_data
}, json_dumps_params={'ensure_ascii': False})
except User.DoesNotExist:
# 用户不存在,创建新用户
new_user = User.objects.create(
email=email,
password=password, # 注意:实际使用时应该哈希存储密码
is_first_login=True,
last_login=datetime.now()
)
return JsonResponse({
'code': 200,
'message': '登录成功',
'data': {
'user_id': new_user.id,
'email': new_user.email,
'is_first_login': True,
'name': None,
'company': None
}
}, 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})
@csrf_exempt
@require_http_methods(["POST"])
def update_user_info(request):
"""更新用户信息,首次登录时填写公司和姓名"""
try:
from .models import User
import json
data = json.loads(request.body)
# 获取参数
user_id = data.get('user_id')
company = data.get('company')
name = data.get('name')
if not user_id:
return JsonResponse({
'code': 400,
'message': '缺少必要参数: user_id',
'data': None
}, json_dumps_params={'ensure_ascii': False})
# 如果是首次登录,需要填写公司和姓名
if not company or not name:
return JsonResponse({
'code': 400,
'message': '首次登录需要填写公司和姓名',
'data': None
}, json_dumps_params={'ensure_ascii': False})
# 查询用户并更新信息
try:
user = User.objects.get(id=user_id)
# 更新信息
user.company = company
user.name = name
user.is_first_login = False # 更新后不再是首次登录
user.save()
return JsonResponse({
'code': 200,
'message': '信息更新成功',
'data': {
'user_id': user.id,
'email': user.email,
'is_first_login': False,
'name': user.name,
'company': user.company
}
}, json_dumps_params={'ensure_ascii': False})
except User.DoesNotExist:
return JsonResponse({
'code': 404,
'message': f'找不到ID为 {user_id} 的用户',
'data': None
}, 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})
@csrf_exempt
@require_http_methods(["POST"])
def user_register(request):
"""用户注册接口,允许用户创建新账户,可选填写公司和姓名"""
try:
from .models import User
import json
from datetime import datetime
data = json.loads(request.body)
# 获取注册参数
email = data.get('email')
password = data.get('password')
company = data.get('company') # 可选参数
name = data.get('name') # 可选参数
# 检查必要参数
if not email or not password:
return JsonResponse({
'code': 400,
'message': '缺少必要参数: email 或 password',
'data': None
}, json_dumps_params={'ensure_ascii': False})
# 检查邮箱是否已注册
if User.objects.filter(email=email).exists():
return JsonResponse({
'code': 409,
'message': '该邮箱已注册',
'data': None
}, json_dumps_params={'ensure_ascii': False})
# 创建用户
try:
# 根据是否提供公司和姓名决定是否为首次登录
is_first_login = not (company and name)
# 创建用户
user = User.objects.create(
email=email,
password=password, # 注意:实际使用时应该哈希存储密码
company=company,
name=name,
is_first_login=is_first_login,
last_login=datetime.now()
)
# 构造返回数据
user_data = {
'user_id': user.id,
'email': user.email,
'is_first_login': is_first_login,
'company': user.company,
'name': user.name
}
return JsonResponse({
'code': 200,
'message': '注册成功',
'data': user_data
}, json_dumps_params={'ensure_ascii': False})
except Exception as e:
logger.error(f"创建用户失败: {e}")
return JsonResponse({
'code': 500,
'message': f'注册失败: {str(e)}',
'data': None
}, 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})

View File

@ -41,14 +41,14 @@ INSTALLED_APPS = [
'django_filters',
'django.contrib.staticfiles',
'channels',
'rest_framework',
'apps.user.apps.UserConfig',
"apps.expertproducts.apps.ExpertproductsConfig",
"apps.daren_detail.apps.DarenDetailConfig",
"apps.discovery.apps.DiscoveryConfig",
"apps.template.apps.TemplateConfig",
"apps.brands.apps.BrandsConfig",
'rest_framework',
'rest_framework_simplejwt',
]
MIDDLEWARE = [
@ -195,34 +195,4 @@ LOGGING = {
'propagate': True,
},
},
}
# 自定义用户模型
AUTH_USER_MODEL = 'user.User'
# REST Framework 设置
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'apps.user.authentication.CustomTokenAuthentication',
),
}
# JWT 设置
from datetime import timedelta
SIMPLE_JWT = {
'ACCESS_TOKEN_LIFETIME': timedelta(days=1),
'REFRESH_TOKEN_LIFETIME': timedelta(days=7),
'ROTATE_REFRESH_TOKENS': False,
'ALGORITHM': 'HS256',
'SIGNING_KEY': SECRET_KEY,
'AUTH_HEADER_TYPES': ('Bearer',),
'USER_ID_FIELD': 'id',
'USER_ID_CLAIM': 'user_id',
'UPDATE_LAST_LOGIN': False, # 不在 token 中记录最后登录时间
'TOKEN_TYPE_CLAIM': None, # 不在 token 中包含 token 类型
'JTI_CLAIM': None, # 不在 token 中包含 JWT ID
}
# JWT配置
JWT_SECRET_KEY = 'your-secret-key-here' # 建议使用更安全的密钥
JWT_EXPIRATION_DELTA = 24 * 60 * 60 # token有效期24小时
}

View File

@ -1,14 +1,8 @@
from django.contrib import admin
from django.urls import path, include
from rest_framework_simplejwt.views import (
TokenObtainPairView,
TokenRefreshView,
)
urlpatterns = [
path('admin/', admin.site.urls),
path('api/token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
path('api/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
path('api/user/', include('apps.user.urls')),
path('api/daren_detail/', include('apps.daren_detail.urls')),
path('api/operation/', include('apps.expertproducts.urls')),