修改多平台更新
This commit is contained in:
parent
16cd0d6624
commit
6a1d3a716e
527
operation/README.md
Normal file
527
operation/README.md
Normal file
@ -0,0 +1,527 @@
|
||||
# Operation 模块接口文档
|
||||
|
||||
## 基础 URL
|
||||
|
||||
所有接口的基础路径: `/api/operation/`
|
||||
|
||||
## 通用响应格式
|
||||
|
||||
所有接口都返回以下格式的响应:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200, // 状态码,200表示成功
|
||||
"message": "操作成功", // 操作结果描述
|
||||
"data": {} // 数据内容,具体格式根据接口不同而变化
|
||||
}
|
||||
```
|
||||
|
||||
分页接口的响应格式:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "获取数据成功",
|
||||
"data": {
|
||||
"count": 100, // 总记录数
|
||||
"next": "http://example.com/api/operation/xxx/?page=2", // 下一页链接,没有下一页则为null
|
||||
"previous": null, // 上一页链接,没有上一页则为null
|
||||
"results": [], // 当前页的数据列表
|
||||
"page": 1, // 当前页码
|
||||
"pages": 10, // 总页数
|
||||
"page_size": 10 // 每页记录数
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 接口列表
|
||||
|
||||
### 1. 运营账号管理
|
||||
|
||||
#### 1.1 获取运营账号列表
|
||||
|
||||
- **URL**: `/operators/`
|
||||
- **方法**: GET
|
||||
- **参数**:
|
||||
- `page`: 页码,默认1
|
||||
- `page_size`: 每页记录数,默认10
|
||||
|
||||
- **响应示例**:
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "获取运营账号列表成功",
|
||||
"data": {
|
||||
"count": 10,
|
||||
"next": null,
|
||||
"previous": null,
|
||||
"results": [
|
||||
{
|
||||
"id": 1,
|
||||
"uuid": "550e8400-e29b-41d4-a716-446655440000",
|
||||
"username": "operator1",
|
||||
"real_name": "张三",
|
||||
"email": "zhangsan@example.com",
|
||||
"phone": "13800138000",
|
||||
"position": "editor",
|
||||
"department": "内容部",
|
||||
"is_active": true,
|
||||
"created_at": "2023-09-01T10:00:00Z",
|
||||
"updated_at": "2023-09-01T10:00:00Z"
|
||||
}
|
||||
],
|
||||
"page": 1,
|
||||
"pages": 1,
|
||||
"page_size": 10
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 1.2 获取运营账号详情
|
||||
|
||||
- **URL**: `/operators/{id}/`
|
||||
- **方法**: GET
|
||||
- **响应示例**:
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "获取运营账号详情成功",
|
||||
"data": {
|
||||
"id": 1,
|
||||
"uuid": "550e8400-e29b-41d4-a716-446655440000",
|
||||
"username": "operator1",
|
||||
"real_name": "张三",
|
||||
"email": "zhangsan@example.com",
|
||||
"phone": "13800138000",
|
||||
"position": "editor",
|
||||
"department": "内容部",
|
||||
"is_active": true,
|
||||
"created_at": "2023-09-01T10:00:00Z",
|
||||
"updated_at": "2023-09-01T10:00:00Z"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 1.3 创建运营账号
|
||||
|
||||
- **URL**: `/operators/`
|
||||
- **方法**: POST
|
||||
- **请求参数**:
|
||||
```json
|
||||
{
|
||||
"username": "operator1",
|
||||
"password": "password123",
|
||||
"real_name": "张三",
|
||||
"email": "zhangsan@example.com",
|
||||
"phone": "13800138000",
|
||||
"position": "editor",
|
||||
"department": "内容部"
|
||||
}
|
||||
```
|
||||
- **响应示例**: 同详情接口
|
||||
|
||||
#### 1.4 更新运营账号
|
||||
|
||||
- **URL**: `/operators/{id}/`
|
||||
- **方法**: PUT/PATCH
|
||||
- **请求参数**: 同创建接口,PATCH 可部分更新
|
||||
- **响应示例**: 同详情接口
|
||||
|
||||
#### 1.5 删除运营账号
|
||||
|
||||
- **URL**: `/operators/{id}/`
|
||||
- **方法**: DELETE
|
||||
- **响应示例**:
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "运营账号已停用",
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 平台账号管理
|
||||
|
||||
#### 2.1 获取平台账号列表
|
||||
|
||||
- **URL**: `/platforms/`
|
||||
- **方法**: GET
|
||||
- **参数**:
|
||||
- `page`: 页码,默认1
|
||||
- `page_size`: 每页记录数,默认10
|
||||
|
||||
- **响应示例**:
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "获取平台账号列表成功",
|
||||
"data": {
|
||||
"count": 10,
|
||||
"next": null,
|
||||
"previous": null,
|
||||
"results": [
|
||||
{
|
||||
"id": 1,
|
||||
"operator": 1,
|
||||
"operator_name": "张三",
|
||||
"status": "active",
|
||||
"followers_count": 1000,
|
||||
"description": "测试账号",
|
||||
"tags": ["科技", "数码"],
|
||||
"profile_image": "https://example.com/image.jpg",
|
||||
"last_posting": "2023-09-01T10:00:00Z",
|
||||
"created_at": "2023-09-01T10:00:00Z",
|
||||
"updated_at": "2023-09-01T10:00:00Z",
|
||||
"last_login": "2023-09-01T10:00:00Z",
|
||||
"platforms": [
|
||||
{
|
||||
"platform_name": "youtube",
|
||||
"account_url": "https://youtube.com/channel/123",
|
||||
"account_id": "channel123",
|
||||
"account_name": "测试频道"
|
||||
}
|
||||
],
|
||||
"name": "youtube"
|
||||
}
|
||||
],
|
||||
"page": 1,
|
||||
"pages": 1,
|
||||
"page_size": 10
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 2.2 获取平台账号详情
|
||||
|
||||
- **URL**: `/platforms/{id}/`
|
||||
- **方法**: GET
|
||||
- **响应示例**: 类似列表但无分页
|
||||
|
||||
#### 2.3 创建平台账号
|
||||
|
||||
- **URL**: `/platforms/`
|
||||
- **方法**: POST
|
||||
- **请求参数**:
|
||||
```json
|
||||
{
|
||||
"operator": 1,
|
||||
"name": "Shizuku",
|
||||
"status": "active",
|
||||
"followers_count": 1000,
|
||||
"description": "测试频道",
|
||||
"tags": ["Vlogs", "Foodie"],
|
||||
"profile_image": "https://example.com/image.jpg",
|
||||
"platforms": [
|
||||
{
|
||||
"platform_name": "youtube",
|
||||
"account_name": "测试频道",
|
||||
"account_id": "channel123",
|
||||
"account_url": "https://youtube.com/channel/123"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
- **响应示例**: 同详情接口
|
||||
|
||||
#### 2.4 更新平台账号
|
||||
|
||||
- **URL**: `/platforms/{id}/`
|
||||
- **方法**: PUT/PATCH
|
||||
- **请求参数**: 同创建接口,PATCH 可部分更新
|
||||
- **响应示例**: 同详情接口
|
||||
|
||||
#### 2.5 删除平台账号
|
||||
|
||||
- **URL**: `/platforms/{id}/`
|
||||
- **方法**: DELETE
|
||||
- **响应示例**:
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "平台账号已删除",
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
#### 2.6 更新粉丝数
|
||||
|
||||
- **URL**: `/platforms/{id}/update_followers/`
|
||||
- **方法**: POST
|
||||
- **请求参数**:
|
||||
```json
|
||||
{
|
||||
"followers_count": 2000
|
||||
}
|
||||
```
|
||||
- **响应示例**: 同详情接口
|
||||
|
||||
#### 2.7 更新账号资料
|
||||
|
||||
- **URL**: `/platforms/{id}/update_profile/`
|
||||
- **方法**: POST
|
||||
- **请求参数**:
|
||||
```json
|
||||
{
|
||||
"tags": ["科技", "数码"],
|
||||
"profile_image": "https://example.com/new_image.jpg",
|
||||
"last_posting": "2023-09-02T10:00:00Z"
|
||||
}
|
||||
```
|
||||
- **响应示例**: 同详情接口
|
||||
|
||||
### 3. 视频管理
|
||||
|
||||
#### 3.1 获取视频列表
|
||||
|
||||
- **URL**: `/videos/`
|
||||
- **方法**: GET
|
||||
- **参数**:
|
||||
- `page`: 页码,默认1
|
||||
- `page_size`: 每页记录数,默认10
|
||||
|
||||
- **响应示例**:
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "获取视频列表成功",
|
||||
"data": {
|
||||
"count": 10,
|
||||
"next": null,
|
||||
"previous": null,
|
||||
"results": [
|
||||
{
|
||||
"id": 1,
|
||||
"platform_account": 1,
|
||||
"platform_account_name": "测试频道",
|
||||
"platform_name": "youtube",
|
||||
"title": "测试视频",
|
||||
"description": "这是一个测试视频",
|
||||
"video_url": "https://youtube.com/watch?v=123",
|
||||
"local_path": "/path/to/video.mp4",
|
||||
"thumbnail_url": "https://example.com/thumb.jpg",
|
||||
"status": "published",
|
||||
"views_count": 1000,
|
||||
"likes_count": 100,
|
||||
"comments_count": 50,
|
||||
"shares_count": 20,
|
||||
"tags": ["测试", "视频"],
|
||||
"publish_time": "2023-09-01T10:00:00Z",
|
||||
"video_id": "v123",
|
||||
"created_at": "2023-09-01T10:00:00Z",
|
||||
"updated_at": "2023-09-01T10:00:00Z"
|
||||
}
|
||||
],
|
||||
"page": 1,
|
||||
"pages": 1,
|
||||
"page_size": 10
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 3.2 获取视频详情
|
||||
|
||||
- **URL**: `/videos/{id}/`
|
||||
- **方法**: GET
|
||||
- **响应示例**: 类似列表但无分页
|
||||
|
||||
#### 3.3 创建视频
|
||||
|
||||
- **URL**: `/videos/`
|
||||
- **方法**: POST
|
||||
- **请求参数**:
|
||||
```json
|
||||
{
|
||||
"platform_account": 1,
|
||||
"title": "测试视频",
|
||||
"description": "这是一个测试视频",
|
||||
"status": "draft",
|
||||
"tags": ["测试", "视频"]
|
||||
}
|
||||
```
|
||||
- **响应示例**: 同详情接口
|
||||
|
||||
#### 3.4 更新视频信息
|
||||
|
||||
- **URL**: `/videos/{id}/`
|
||||
- **方法**: PUT/PATCH
|
||||
- **请求参数**: 同创建接口,PATCH 可部分更新
|
||||
- **响应示例**: 同详情接口
|
||||
|
||||
#### 3.5 删除视频
|
||||
|
||||
- **URL**: `/videos/{id}/`
|
||||
- **方法**: DELETE
|
||||
- **响应示例**:
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "视频记录已删除",
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
#### 3.6 更新视频统计数据
|
||||
|
||||
- **URL**: `/videos/{id}/update_stats/`
|
||||
- **方法**: POST
|
||||
- **请求参数**:
|
||||
```json
|
||||
{
|
||||
"views_count": 2000,
|
||||
"likes_count": 200,
|
||||
"comments_count": 100,
|
||||
"shares_count": 50
|
||||
}
|
||||
```
|
||||
- **响应示例**:
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "视频统计数据更新成功",
|
||||
"data": {
|
||||
"id": 1,
|
||||
"title": "测试视频",
|
||||
"views_count": 2000,
|
||||
"likes_count": 200,
|
||||
"comments_count": 100,
|
||||
"shares_count": 50
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 3.7 发布视频
|
||||
|
||||
- **URL**: `/videos/{id}/publish/`
|
||||
- **方法**: POST
|
||||
- **请求参数**:
|
||||
```json
|
||||
{
|
||||
"video_url": "https://youtube.com/watch?v=123"
|
||||
}
|
||||
```
|
||||
- **响应示例**:
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "视频已成功发布",
|
||||
"data": {
|
||||
"id": 1,
|
||||
"title": "测试视频",
|
||||
"status": "published",
|
||||
"video_url": "https://youtube.com/watch?v=123",
|
||||
"publish_time": "2023-09-02T10:00:00Z"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 3.8 上传视频
|
||||
|
||||
- **URL**: `/videos/upload_video/`
|
||||
- **方法**: POST
|
||||
- **请求参数**:
|
||||
- `video_file`: 视频文件(multipart/form-data)
|
||||
- `platform_account`: 平台账号ID
|
||||
- `title`: 视频标题
|
||||
- `description`: 视频描述
|
||||
- `tags`: 视频标签
|
||||
|
||||
- **响应示例**:
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "视频上传成功",
|
||||
"data": {
|
||||
"id": 1,
|
||||
"title": "测试视频",
|
||||
"status": "draft"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 3.9 手动发布视频
|
||||
|
||||
- **URL**: `/videos/{id}/manual_publish/`
|
||||
- **方法**: POST
|
||||
- **请求参数**:
|
||||
```json
|
||||
{
|
||||
"video_url": "https://youtube.com/watch?v=123"
|
||||
}
|
||||
```
|
||||
- **响应示例**:
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "视频发布成功",
|
||||
"data": {
|
||||
"id": 1,
|
||||
"title": "测试视频",
|
||||
"status": "published",
|
||||
"video_url": "https://youtube.com/watch?v=123",
|
||||
"publish_time": "2023-09-02T10:00:00Z"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 字段说明
|
||||
|
||||
### 运营账号(OperatorAccount)
|
||||
|
||||
| 字段名 | 类型 | 说明 |
|
||||
|------------|-----------|--------------------------------------------------|
|
||||
| id | Integer | 自增主键ID |
|
||||
| uuid | UUID | 唯一标识符 |
|
||||
| username | String | 用户名 |
|
||||
| password | String | 密码(创建/更新时传入,不会在响应中返回) |
|
||||
| real_name | String | 真实姓名 |
|
||||
| email | String | 邮箱 |
|
||||
| phone | String | 电话号码 |
|
||||
| position | String | 职位,可选值: editor(编辑)、planner(策划)、operator(运营)、admin(管理员) |
|
||||
| department | String | 部门 |
|
||||
| is_active | Boolean | 是否在职 |
|
||||
| created_at | Datetime | 创建时间 |
|
||||
| updated_at | Datetime | 更新时间 |
|
||||
|
||||
### 平台账号(PlatformAccount)
|
||||
|
||||
| 字段名 | 类型 | 说明 |
|
||||
|----------------|-----------|--------------------------------------------------|
|
||||
| id | Integer | 自增主键ID |
|
||||
| operator | Integer | 关联运营账号ID |
|
||||
| operator_name | String | 运营账号名称(只读) |
|
||||
| name | String | 自定义账户名称,可用于分类和识别不同平台的账号 |
|
||||
| platforms | Array | 平台信息数组,包含平台名称、账号名称、账号ID、账号URL |
|
||||
| status | String | 账号状态,可选值: active(正常)、restricted(限流)、suspended(封禁)、inactive(未激活) |
|
||||
| followers_count| Integer | 粉丝数 |
|
||||
| description | String | 账号描述 |
|
||||
| tags | Array | 标签数组 |
|
||||
| profile_image | String | 账号头像URL |
|
||||
| last_posting | Datetime | 最后发布时间 |
|
||||
| created_at | Datetime | 创建时间 |
|
||||
| updated_at | Datetime | 更新时间 |
|
||||
| last_login | Datetime | 最后登录时间 |
|
||||
|
||||
### 视频(Video)
|
||||
|
||||
| 字段名 | 类型 | 说明 |
|
||||
|----------------------|-----------|--------------------------------------------------|
|
||||
| id | Integer | 自增主键ID |
|
||||
| platform_account | Integer | 关联平台账号ID |
|
||||
| platform_account_name| String | 平台账号名称(只读) |
|
||||
| platform_name | String | 平台名称(只读) |
|
||||
| title | String | 视频标题 |
|
||||
| description | String | 视频描述 |
|
||||
| video_url | String | 视频URL |
|
||||
| local_path | String | 本地存储路径 |
|
||||
| thumbnail_url | String | 缩略图URL |
|
||||
| status | String | 视频状态,可选值: draft(草稿)、scheduled(已排期)、published(已发布)、failed(失败)、deleted(已删除) |
|
||||
| views_count | Integer | 观看次数 |
|
||||
| likes_count | Integer | 点赞数 |
|
||||
| comments_count | Integer | 评论数 |
|
||||
| shares_count | Integer | 分享数 |
|
||||
| tags | Array | 标签数组 |
|
||||
| publish_time | Datetime | 发布时间 |
|
||||
| video_id | String | 视频ID |
|
||||
| created_at | Datetime | 创建时间 |
|
||||
| updated_at | Datetime | 更新时间 |
|
||||
</rewritten_file>
|
@ -0,0 +1,59 @@
|
||||
# Generated by Django 5.1.5 on 2025-05-15 03:09
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('operation', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name='platformaccount',
|
||||
options={'ordering': ['-created_at'], 'verbose_name': '平台账号', 'verbose_name_plural': '平台账号'},
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='platformaccount',
|
||||
unique_together=set(),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='platformaccount',
|
||||
name='name',
|
||||
field=models.CharField(blank=True, default='', max_length=100, verbose_name='账户名称'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='platformaccount',
|
||||
name='operator',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='platform_accounts', to='operation.operatoraccount', verbose_name='运营账号'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='platformaccount',
|
||||
name='platform_name',
|
||||
field=models.CharField(choices=[('youtube', 'YouTube'), ('tiktok', 'TikTok'), ('bilibili', 'Bilibili'), ('facebook', 'Facebook'), ('instagram', 'Instagram'), ('twitter', 'Twitter'), ('other', '其他平台')], max_length=20, verbose_name='平台名称'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='platformaccount',
|
||||
name='profile_image',
|
||||
field=models.URLField(blank=True, null=True, verbose_name='头像URL'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='platformaccount',
|
||||
name='tags',
|
||||
field=models.CharField(blank=True, help_text='逗号分隔的标签列表', max_length=255, null=True, verbose_name='标签'),
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name='platformaccount',
|
||||
index=models.Index(fields=['platform_name'], name='operation_p_platfor_6e8678_idx'),
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name='platformaccount',
|
||||
index=models.Index(fields=['account_id'], name='operation_p_account_bdceaf_idx'),
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name='platformaccount',
|
||||
index=models.Index(fields=['status'], name='operation_p_status_167573_idx'),
|
||||
),
|
||||
]
|
@ -38,25 +38,26 @@ class OperatorAccount(models.Model):
|
||||
return f"{self.real_name} ({self.username})"
|
||||
|
||||
class PlatformAccount(models.Model):
|
||||
"""平台账号信息表"""
|
||||
"""平台账号模型"""
|
||||
PLATFORM_CHOICES = [
|
||||
('youtube', 'YouTube'),
|
||||
('tiktok', 'TikTok'),
|
||||
('bilibili', 'Bilibili'),
|
||||
('facebook', 'Facebook'),
|
||||
('instagram', 'Instagram'),
|
||||
('twitter', 'Twitter'),
|
||||
('other', '其他平台')
|
||||
]
|
||||
|
||||
STATUS_CHOICES = [
|
||||
('active', '正常'),
|
||||
('restricted', '限流'),
|
||||
('suspended', '封禁'),
|
||||
('inactive', '未激活'),
|
||||
('inactive', '未激活')
|
||||
]
|
||||
|
||||
PLATFORM_CHOICES = [
|
||||
('youtube', 'YouTube'),
|
||||
('tiktok', 'TikTok'),
|
||||
('twitter', 'Twitter/X'),
|
||||
('instagram', 'Instagram'),
|
||||
('facebook', 'Facebook'),
|
||||
('bilibili', 'Bilibili'),
|
||||
]
|
||||
|
||||
operator = models.ForeignKey(OperatorAccount, on_delete=models.CASCADE, related_name='platform_accounts', verbose_name='关联运营')
|
||||
operator = models.ForeignKey(OperatorAccount, on_delete=models.CASCADE, related_name='platform_accounts', verbose_name='运营账号')
|
||||
name = models.CharField(max_length=100, verbose_name='账户名称', default='', blank=True)
|
||||
platform_name = models.CharField(max_length=20, choices=PLATFORM_CHOICES, verbose_name='平台名称')
|
||||
account_name = models.CharField(max_length=100, verbose_name='账号名称')
|
||||
account_id = models.CharField(max_length=100, verbose_name='账号ID')
|
||||
@ -64,23 +65,25 @@ class PlatformAccount(models.Model):
|
||||
followers_count = models.IntegerField(default=0, verbose_name='粉丝数')
|
||||
account_url = models.URLField(blank=True, null=True, verbose_name='账号链接')
|
||||
description = models.TextField(blank=True, null=True, verbose_name='账号描述')
|
||||
|
||||
# 新增字段
|
||||
tags = models.CharField(max_length=255, blank=True, null=True, verbose_name='标签', help_text='用逗号分隔的标签列表')
|
||||
profile_image = models.URLField(blank=True, null=True, verbose_name='账号头像')
|
||||
tags = models.CharField(max_length=255, blank=True, null=True, verbose_name='标签', help_text='逗号分隔的标签列表')
|
||||
profile_image = models.URLField(blank=True, null=True, verbose_name='头像URL')
|
||||
last_posting = 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='更新时间')
|
||||
last_login = models.DateTimeField(blank=True, null=True, verbose_name='最后登录时间')
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.platform_name} - {self.account_name}"
|
||||
|
||||
class Meta:
|
||||
verbose_name = '平台账号'
|
||||
verbose_name_plural = '平台账号'
|
||||
unique_together = ('platform_name', 'account_id')
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.account_name} ({self.get_platform_name_display()})"
|
||||
ordering = ['-created_at']
|
||||
indexes = [
|
||||
models.Index(fields=['platform_name']),
|
||||
models.Index(fields=['account_id']),
|
||||
models.Index(fields=['status']),
|
||||
]
|
||||
|
||||
class Video(models.Model):
|
||||
"""视频信息表"""
|
||||
|
@ -8,12 +8,13 @@ class CustomPagination(PageNumberPagination):
|
||||
max_page_size = 100
|
||||
|
||||
def get_paginated_response(self, data):
|
||||
# 为每个结果添加name字段,从platforms中提取平台名称
|
||||
# 为那些没有name字段或name字段为空的项目设置默认值
|
||||
for item in data:
|
||||
if 'platforms' in item and len(item['platforms']) > 0:
|
||||
# 添加name字段,只使用platform_name
|
||||
platform = item['platforms'][0]
|
||||
item['name'] = platform.get('platform_name', '')
|
||||
# 只有当name为空或不存在时,才使用platform_name作为默认值
|
||||
if not item.get('name'):
|
||||
platform = item['platforms'][0]
|
||||
item['name'] = platform.get('platform_name', '')
|
||||
|
||||
return Response({
|
||||
"code": 200,
|
||||
|
@ -18,15 +18,20 @@ class OperatorAccountSerializer(serializers.ModelSerializer):
|
||||
|
||||
class PlatformAccountSerializer(serializers.ModelSerializer):
|
||||
operator_name = serializers.CharField(source='operator.real_name', read_only=True)
|
||||
platforms = serializers.SerializerMethodField()
|
||||
|
||||
class Meta:
|
||||
model = PlatformAccount
|
||||
fields = ['id', 'operator', 'operator_name', 'platform_name', 'account_name', 'account_id',
|
||||
fields = ['id', 'operator', 'operator_name', 'name', 'platform_name', 'account_name', 'account_id',
|
||||
'status', 'followers_count', 'account_url', 'description',
|
||||
'tags', 'profile_image', 'last_posting',
|
||||
'created_at', 'updated_at', 'last_login']
|
||||
'created_at', 'updated_at', 'last_login', 'platforms']
|
||||
read_only_fields = ['id', 'created_at', 'updated_at']
|
||||
|
||||
def get_platforms(self, obj):
|
||||
# 不会在查询时调用,但需要实现该方法,默认返回空数组
|
||||
return []
|
||||
|
||||
def to_internal_value(self, data):
|
||||
# 处理operator字段,可能是字符串格式的ID
|
||||
if 'operator' in data and isinstance(data['operator'], str):
|
||||
@ -41,6 +46,28 @@ class PlatformAccountSerializer(serializers.ModelSerializer):
|
||||
# 其他类型的错误,如ID格式不正确等
|
||||
pass
|
||||
|
||||
# 处理platforms字段,从数组中提取出第一个元素的信息
|
||||
if 'platforms' in data and isinstance(data['platforms'], list) and len(data['platforms']) > 0:
|
||||
data = data.copy()
|
||||
platform_data = data['platforms'][0]
|
||||
# 将platforms中的字段移到顶层
|
||||
if 'platform_name' in platform_data:
|
||||
data['platform_name'] = platform_data['platform_name']
|
||||
if 'account_url' in platform_data:
|
||||
data['account_url'] = platform_data['account_url']
|
||||
if 'account_id' in platform_data:
|
||||
data['account_id'] = platform_data['account_id']
|
||||
if 'account_name' in platform_data:
|
||||
data['account_name'] = platform_data['account_name']
|
||||
|
||||
# 删除platforms字段,避免验证错误
|
||||
del data['platforms']
|
||||
|
||||
# 处理tags字段,将列表转换为逗号分隔的字符串
|
||||
if 'tags' in data and isinstance(data['tags'], list):
|
||||
data = data.copy() if not isinstance(data, dict) else data
|
||||
data['tags'] = ','.join(data['tags'])
|
||||
|
||||
return super().to_internal_value(data)
|
||||
|
||||
def to_representation(self, instance):
|
||||
@ -60,6 +87,7 @@ class PlatformDetailSerializer(serializers.Serializer):
|
||||
class MultiPlatformAccountSerializer(serializers.Serializer):
|
||||
"""多平台账号创建序列化器"""
|
||||
operator = serializers.PrimaryKeyRelatedField(queryset=OperatorAccount.objects.all())
|
||||
name = serializers.CharField(max_length=100, required=False, allow_blank=True)
|
||||
account_name = serializers.CharField(max_length=100)
|
||||
account_id = serializers.CharField(max_length=100)
|
||||
status = serializers.ChoiceField(choices=PlatformAccount.STATUS_CHOICES, default='active')
|
||||
|
@ -124,8 +124,9 @@ class PlatformAccountViewSet(viewsets.ModelViewSet):
|
||||
}
|
||||
# 添加platforms字段作为数组
|
||||
account_data["platforms"] = [platform_info]
|
||||
# 添加name字段,只用platform_name
|
||||
account_data["name"] = platform_info["platform_name"]
|
||||
# 保留用户传入的name字段,如果没有则使用platform_name
|
||||
if not account_data.get("name"):
|
||||
account_data["name"] = platform_info["platform_name"]
|
||||
restructured_data.append(account_data)
|
||||
|
||||
# 使用自定义分页器的响应,但替换数据
|
||||
@ -145,8 +146,9 @@ class PlatformAccountViewSet(viewsets.ModelViewSet):
|
||||
}
|
||||
# 添加platforms字段作为数组
|
||||
account_data["platforms"] = [platform_info]
|
||||
# 添加name字段,只用platform_name
|
||||
account_data["name"] = platform_info["platform_name"]
|
||||
# 保留用户传入的name字段,如果没有则使用platform_name
|
||||
if not account_data.get("name"):
|
||||
account_data["name"] = platform_info["platform_name"]
|
||||
restructured_data.append(account_data)
|
||||
|
||||
return Response({
|
||||
@ -170,8 +172,9 @@ class PlatformAccountViewSet(viewsets.ModelViewSet):
|
||||
}
|
||||
# 添加platforms字段
|
||||
account_data["platforms"] = [platform_info]
|
||||
# 添加name字段,只用platform_name
|
||||
account_data["name"] = platform_info["platform_name"]
|
||||
# 保留用户传入的name字段,如果没有则使用platform_name
|
||||
if not account_data.get("name"):
|
||||
account_data["name"] = platform_info["platform_name"]
|
||||
|
||||
return Response({
|
||||
"code": 200,
|
||||
@ -183,10 +186,50 @@ class PlatformAccountViewSet(viewsets.ModelViewSet):
|
||||
"""更新平台账号信息"""
|
||||
partial = kwargs.pop('partial', False)
|
||||
instance = self.get_object()
|
||||
serializer = self.get_serializer(instance, data=request.data, partial=partial)
|
||||
|
||||
# 单独处理platforms字段,多平台信息需要特殊处理
|
||||
data = request.data.copy()
|
||||
platforms_data = None
|
||||
|
||||
if 'platforms' in data and isinstance(data['platforms'], list):
|
||||
platforms_data = data.pop('platforms')
|
||||
|
||||
# 如果有platforms数据,先将第一个平台的信息移至顶层,保证基本平台信息能正常更新
|
||||
if platforms_data and len(platforms_data) > 0:
|
||||
first_platform = platforms_data[0]
|
||||
if 'platform_name' in first_platform:
|
||||
data['platform_name'] = first_platform['platform_name']
|
||||
if 'account_url' in first_platform:
|
||||
data['account_url'] = first_platform['account_url']
|
||||
if 'account_id' in first_platform:
|
||||
data['account_id'] = first_platform['account_id']
|
||||
if 'account_name' in first_platform:
|
||||
data['account_name'] = first_platform['account_name']
|
||||
|
||||
serializer = self.get_serializer(instance, data=data, partial=partial)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
self.perform_update(serializer)
|
||||
|
||||
# 处理多平台信息
|
||||
# 这里我们需要实现新的逻辑来处理额外的平台
|
||||
# 注意:这需要修改模型结构或添加关联模型来支持多平台
|
||||
# 由于当前模型结构限制,我们暂时只能在此记录其他平台数据
|
||||
# 用于未来扩展,目前会在日志中记录这些信息
|
||||
if platforms_data and len(platforms_data) > 1:
|
||||
logger = logging.getLogger(__name__)
|
||||
logger.info(f"接收到多平台数据,但当前版本仅支持一个平台。额外平台数据: {platforms_data[1:]}")
|
||||
|
||||
# 这里应该添加创建关联平台记录的代码
|
||||
# 例如:
|
||||
# for platform_data in platforms_data[1:]:
|
||||
# RelatedPlatform.objects.create(
|
||||
# primary_account=instance,
|
||||
# platform_name=platform_data.get('platform_name', ''),
|
||||
# account_id=platform_data.get('account_id', ''),
|
||||
# account_name=platform_data.get('account_name', ''),
|
||||
# account_url=platform_data.get('account_url', '')
|
||||
# )
|
||||
|
||||
# 处理数据结构
|
||||
account_data = serializer.data
|
||||
# 提取平台信息并放入platforms字段
|
||||
@ -197,9 +240,15 @@ class PlatformAccountViewSet(viewsets.ModelViewSet):
|
||||
"account_name": account_data.pop("account_name")
|
||||
}
|
||||
# 添加platforms字段
|
||||
account_data["platforms"] = [platform_info]
|
||||
# 添加name字段
|
||||
account_data["name"] = platform_info["platform_name"] + " | " + platform_info["account_name"]
|
||||
# 如果有platforms_data,使用原始请求中的数据,否则使用当前的单平台数据
|
||||
if platforms_data:
|
||||
account_data["platforms"] = platforms_data
|
||||
else:
|
||||
account_data["platforms"] = [platform_info]
|
||||
|
||||
# 保留用户传入的name字段,如果没有则使用platform_name
|
||||
if not account_data.get("name"):
|
||||
account_data["name"] = platform_info["platform_name"]
|
||||
|
||||
return Response({
|
||||
"code": 200,
|
||||
@ -214,120 +263,69 @@ class PlatformAccountViewSet(viewsets.ModelViewSet):
|
||||
|
||||
def create(self, request, *args, **kwargs):
|
||||
"""创建平台账号"""
|
||||
# 检查请求数据中是否包含platforms字段,判断是否为多平台账号创建
|
||||
if 'platforms' in request.data and isinstance(request.data['platforms'], list):
|
||||
# 使用多平台账号序列化器
|
||||
serializer = MultiPlatformAccountSerializer(data=request.data)
|
||||
# 传统单平台账号创建流程
|
||||
print(f"{request.data}")
|
||||
with transaction.atomic():
|
||||
# 处理operator字段,可能是字符串类型的ID
|
||||
data = request.data.copy()
|
||||
if 'operator' in data and isinstance(data['operator'], str):
|
||||
try:
|
||||
# 尝试通过ID查找运营账号
|
||||
operator_id = data['operator']
|
||||
try:
|
||||
# 先尝试通过整数ID查找
|
||||
operator_id_int = int(operator_id)
|
||||
operator = OperatorAccount.objects.get(id=operator_id_int)
|
||||
except (ValueError, OperatorAccount.DoesNotExist):
|
||||
# 如果无法转换为整数或找不到对应账号,尝试通过用户名或真实姓名查找
|
||||
operator = OperatorAccount.objects.filter(
|
||||
Q(username=operator_id) | Q(real_name=operator_id)
|
||||
).first()
|
||||
|
||||
if not operator:
|
||||
return Response({
|
||||
"code": 404,
|
||||
"message": f"未找到运营账号: {operator_id},请提供有效的ID、用户名或真实姓名",
|
||||
"data": None
|
||||
}, status=status.HTTP_404_NOT_FOUND)
|
||||
|
||||
# 更新请求数据中的operator字段为找到的operator的ID
|
||||
data['operator'] = operator.id
|
||||
|
||||
except Exception as e:
|
||||
return Response({
|
||||
"code": 400,
|
||||
"message": f"处理运营账号ID时出错: {str(e)}",
|
||||
"data": None
|
||||
}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
# 创建平台账号
|
||||
serializer = self.get_serializer(data=data)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
|
||||
created_accounts = []
|
||||
# 创建平台账号
|
||||
self.perform_create(serializer)
|
||||
|
||||
with transaction.atomic():
|
||||
# 获取基础账号信息
|
||||
base_data = serializer.validated_data.copy()
|
||||
platforms_data = base_data.pop('platforms')
|
||||
operator = base_data['operator']
|
||||
|
||||
# 遍历平台数据创建多个平台账号
|
||||
for platform_data in platforms_data:
|
||||
# 创建平台账号数据
|
||||
platform_account_data = base_data.copy()
|
||||
platform_account_data['platform_name'] = platform_data['platform_name']
|
||||
platform_account_data['account_url'] = platform_data['platform_url']
|
||||
|
||||
# 创建平台账号
|
||||
platform_account = PlatformAccount.objects.create(**platform_account_data)
|
||||
created_accounts.append(platform_account)
|
||||
|
||||
# 将创建的账号序列化返回
|
||||
result_serializer = self.get_serializer(created_accounts, many=True)
|
||||
# 修改响应数据结构
|
||||
response_data = result_serializer.data
|
||||
|
||||
# 重新组织数据格式
|
||||
restructured_data = []
|
||||
for account_data in response_data:
|
||||
# 提取平台信息并放入platforms字段
|
||||
platform_info = {
|
||||
"platform_name": account_data.pop("platform_name"),
|
||||
"account_url": account_data.pop("account_url"),
|
||||
"account_id": account_data.pop("account_id"),
|
||||
"account_name": account_data.pop("account_name")
|
||||
}
|
||||
|
||||
# 添加platforms字段
|
||||
account_data["platforms"] = [platform_info]
|
||||
# 添加name字段,只用platform_name
|
||||
account_data["name"] = platform_info["platform_name"]
|
||||
restructured_data.append(account_data)
|
||||
|
||||
return Response({
|
||||
"code": 200,
|
||||
"message": "多平台账号创建成功",
|
||||
"data": restructured_data
|
||||
}, status=status.HTTP_201_CREATED)
|
||||
else:
|
||||
# 传统单平台账号创建流程
|
||||
with transaction.atomic():
|
||||
# 处理operator字段,可能是字符串类型的ID
|
||||
data = request.data.copy()
|
||||
if 'operator' in data and isinstance(data['operator'], str):
|
||||
try:
|
||||
# 尝试通过ID查找运营账号
|
||||
operator_id = data['operator']
|
||||
try:
|
||||
# 先尝试通过整数ID查找
|
||||
operator_id_int = int(operator_id)
|
||||
operator = OperatorAccount.objects.get(id=operator_id_int)
|
||||
except (ValueError, OperatorAccount.DoesNotExist):
|
||||
# 如果无法转换为整数或找不到对应账号,尝试通过用户名或真实姓名查找
|
||||
operator = OperatorAccount.objects.filter(
|
||||
Q(username=operator_id) | Q(real_name=operator_id)
|
||||
).first()
|
||||
|
||||
if not operator:
|
||||
return Response({
|
||||
"code": 404,
|
||||
"message": f"未找到运营账号: {operator_id},请提供有效的ID、用户名或真实姓名",
|
||||
"data": None
|
||||
}, status=status.HTTP_404_NOT_FOUND)
|
||||
|
||||
# 更新请求数据中的operator字段为找到的operator的ID
|
||||
data['operator'] = operator.id
|
||||
|
||||
except Exception as e:
|
||||
return Response({
|
||||
"code": 400,
|
||||
"message": f"处理运营账号ID时出错: {str(e)}",
|
||||
"data": None
|
||||
}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
# 创建平台账号
|
||||
serializer = self.get_serializer(data=data)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
|
||||
# 创建平台账号
|
||||
self.perform_create(serializer)
|
||||
|
||||
# 处理响应数据
|
||||
account_data = serializer.data
|
||||
# 提取平台信息并放入platforms字段
|
||||
platform_info = {
|
||||
"platform_name": account_data.pop("platform_name"),
|
||||
"account_url": account_data.pop("account_url"),
|
||||
"account_id": account_data.pop("account_id"),
|
||||
"account_name": account_data.pop("account_name")
|
||||
}
|
||||
# 添加platforms字段
|
||||
account_data["platforms"] = [platform_info]
|
||||
# 添加name字段,只用platform_name
|
||||
# 处理响应数据
|
||||
account_data = serializer.data
|
||||
# 提取平台信息并放入platforms字段
|
||||
platform_info = {
|
||||
"platform_name": account_data.pop("platform_name"),
|
||||
"account_url": account_data.pop("account_url"),
|
||||
"account_id": account_data.pop("account_id"),
|
||||
"account_name": account_data.pop("account_name")
|
||||
}
|
||||
# 添加platforms字段
|
||||
account_data["platforms"] = [platform_info]
|
||||
# 保留用户传入的name字段,如果没有则使用platform_name
|
||||
if not account_data.get("name"):
|
||||
account_data["name"] = platform_info["platform_name"]
|
||||
|
||||
return Response({
|
||||
"code": 200,
|
||||
"message": "平台账号创建成功",
|
||||
"data": account_data
|
||||
}, status=status.HTTP_201_CREATED)
|
||||
return Response({
|
||||
"code": 200,
|
||||
"message": "平台账号创建成功",
|
||||
"data": account_data
|
||||
}, status=status.HTTP_201_CREATED)
|
||||
|
||||
def destroy(self, request, *args, **kwargs):
|
||||
"""删除平台账号"""
|
||||
@ -368,8 +366,9 @@ class PlatformAccountViewSet(viewsets.ModelViewSet):
|
||||
}
|
||||
# 添加platforms字段
|
||||
platform_data["platforms"] = [platform_info]
|
||||
# 添加name字段,只用platform_name
|
||||
platform_data["name"] = platform_info["platform_name"]
|
||||
# 保留用户传入的name字段,如果没有则使用platform_name
|
||||
if not platform_data.get("name"):
|
||||
platform_data["name"] = platform_info["platform_name"]
|
||||
|
||||
return Response({
|
||||
"code": 200,
|
||||
@ -412,6 +411,10 @@ class PlatformAccountViewSet(viewsets.ModelViewSet):
|
||||
"data": None
|
||||
}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
# 处理名称
|
||||
if 'name' in request.data:
|
||||
profile_data['name'] = request.data['name']
|
||||
|
||||
if not profile_data:
|
||||
return Response({
|
||||
"code": 400,
|
||||
@ -435,8 +438,9 @@ class PlatformAccountViewSet(viewsets.ModelViewSet):
|
||||
}
|
||||
# 添加platforms字段
|
||||
platform_data["platforms"] = [platform_info]
|
||||
# 添加name字段,只用platform_name
|
||||
platform_data["name"] = platform_info["platform_name"]
|
||||
# 保留用户传入的name字段,如果没有则使用platform_name
|
||||
if not platform_data.get("name"):
|
||||
platform_data["name"] = platform_info["platform_name"]
|
||||
|
||||
return Response({
|
||||
"code": 200,
|
||||
|
Loading…
Reference in New Issue
Block a user