You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过视图按钮调用已创建对象的类函数(Django+Keras)

解决Django按钮触发多阶段耗时任务的方案

嘿,我明白你现在的困境——用Django搭Keras应用,那些预处理、训练步骤太费时间,同步跑肯定会超时,还想拆成多阶段用按钮触发对吧?别担心,咱们一步步来解决,核心是用异步任务处理耗时操作,再把前端按钮和后端的任务触发逻辑绑定起来。

首先明确核心思路

因为你的任务都是长时间运行的,绝对不能用Django的普通同步视图(用户点完按钮就得一直等,还容易超时)。正确的做法是:

  1. 前端按钮通过AJAX发送请求(不用刷新页面)
  2. 后端启动异步任务(用Celery管理,这是Django处理耗时任务的标准方案)
  3. 实时跟踪任务状态,给用户反馈进度
  4. 任务完成后展示结果

1. 前端:给按钮绑定触发逻辑

先在Django模板里写按钮和状态展示区域,用AJAX和后端交互,这样用户不用刷新页面就能看到进度。示例代码如下:

<!-- 文档上传表单 -->
<form id="docUploadForm" enctype="multipart/form-data">
  {% csrf_token %}
  <input type="file" name="uploaded_doc" id="docInput" required>
  <button type="button" id="startProcessBtn">启动全流程(预处理+训练)</button>
</form>

<!-- 进度展示区 -->
<div id="taskProgress" style="margin-top: 20px; padding: 10px; border: 1px solid #eee;"></div>

<script>
// 绑定按钮点击事件
document.getElementById('startProcessBtn').addEventListener('click', function() {
  const formData = new FormData(document.getElementById('docUploadForm'));
  
  // 发送POST请求到后端启动任务
  fetch('/trigger-process/', {
    method: 'POST',
    body: formData,
    headers: {
      'X-CSRFToken': document.querySelector('[name=csrfmiddlewaretoken]').value
    }
  })
  .then(res => res.json())
  .then(data => {
    // 拿到任务ID,开始轮询状态
    const taskId = data.task_id;
    setInterval(() => checkTaskStatus(taskId), 2000);
  })
  .catch(err => {
    document.getElementById('taskProgress').textContent = '请求失败,请重试';
  });
});

// 轮询任务状态
function checkTaskStatus(taskId) {
  fetch(`/task-status/${taskId}/`)
  .then(res => res.json())
  .then(data => {
    const progressBox = document.getElementById('taskProgress');
    progressBox.textContent = `当前状态:${data.status}`;
    
    if (data.state === 'SUCCESS') {
      // 任务完成,展示结果
      progressBox.innerHTML += `<br>训练结果:${JSON.stringify(data.result)}`;
      // 这里也可以跳转到专门的结果页面
    } else if (data.state === 'FAILURE') {
      progressBox.textContent += ' → 任务失败,请检查日志';
    }
  });
}
</script>

2. 后端:配置异步任务+视图处理

第一步:安装并配置Celery

Celery是Django生态里处理异步任务的首选工具,需要搭配消息代理(比如Redis或RabbitMQ)。先安装依赖:

pip install celery redis

然后在项目根目录配置Celery(具体配置可以参考Celery官方文档,这里只说核心部分)。

第二步:写异步任务函数

把你的预处理、训练、结果整理逻辑拆成阶段,用Celery任务包装,还能实时更新任务状态:

# your_app/tasks.py
from celery import shared_task
from django.core.files.storage import default_storage
import numpy as np
from keras.models import Sequential
from keras.layers import Dense

@shared_task(bind=True)
def full_process_task(self, doc_path):
    # 阶段1:文档预处理
    self.update_state(state='PREPROCESSING', meta={'status': '正在清洗、转换文档数据...'})
    processed_data = preprocess_uploaded_doc(doc_path)
    
    # 阶段2:模型训练
    self.update_state(state='TRAINING', meta={'status': '模型训练中,这可能需要几分钟...'})
    model_result = train_keras_model(processed_data)
    
    # 阶段3:完成任务,返回结果
    self.update_state(state='SUCCESS', meta={'status': '任务完成!', 'result': model_result})
    return model_result

# 自定义预处理函数(替换成你自己的逻辑)
def preprocess_uploaded_doc(doc_path):
    with default_storage.open(doc_path) as f:
        content = f.read().decode('utf-8')
    # 这里写你的文本清洗、特征提取等逻辑,返回模型需要的数据格式
    return {
        'X_train': np.random.rand(100, 10),  # 示例数据
        'y_train': np.random.randint(0, 2, 100),
        'X_test': np.random.rand(20, 10),
        'y_test': np.random.randint(0, 2, 20)
    }

# 自定义Keras训练函数(替换成你自己的模型)
def train_keras_model(data):
    model = Sequential([
        Dense(32, activation='relu', input_shape=(10,)),
        Dense(1, activation='sigmoid')
    ])
    model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])
    model.fit(data['X_train'], data['y_train'], epochs=5)
    loss, accuracy = model.evaluate(data['X_test'], data['y_test'])
    return {'loss': float(loss), 'accuracy': float(accuracy)}

第三步:写Django视图处理请求

创建视图来接收前端的请求,启动任务,以及返回任务状态:

# your_app/views.py
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
from .tasks import full_process_task
from django.core.files.storage import default_storage
from django.core.files.base import ContentFile

@csrf_exempt
def trigger_process(request):
    if request.method == 'POST':
        uploaded_doc = request.FILES.get('uploaded_doc')
        if not uploaded_doc:
            return JsonResponse({'error': '请选择文档'}, status=400)
        
        # 保存上传的文档到服务器
        doc_path = default_storage.save(f'uploads/{uploaded_doc.name}', ContentFile(uploaded_doc.read()))
        # 启动异步任务
        task = full_process_task.delay(doc_path)
        
        return JsonResponse({'task_id': task.id})
    return JsonResponse({'error': '无效请求'}, status=400)

def task_status(request, task_id):
    task = full_process_task.AsyncResult(task_id)
    
    if task.state == 'PENDING':
        response = {'state': task.state, 'status': '任务等待调度...'}
    elif task.state != 'FAILURE':
        response = {
            'state': task.state,
            'status': task.info.get('status', '处理中...')
        }
        if 'result' in task.info:
            response['result'] = task.info['result']
    else:
        # 任务失败,返回错误信息
        response = {'state': task.state, 'status': f'错误:{str(task.info)}'}
    
    return JsonResponse(response)

第四步:配置URL路由

把视图和URL绑定起来:

# your_app/urls.py
from django.urls import path
from . import views

urlpatterns = [
    path('trigger-process/', views.trigger_process, name='trigger_process'),
    path('task-status/<str:task_id>/', views.task_status, name='task_status'),
]

3. 拆分成独立阶段的进阶方案

如果你想把预处理、训练、结果展示拆成独立的按钮触发(比如用户先上传文档→点按钮预处理→再点按钮训练),可以这么做:

  1. 新建一个TaskRecord模型,记录每个任务的状态、文档路径、中间结果等
  2. 把每个阶段拆成单独的Celery任务(比如preprocess_task、train_task)
  3. 前端根据TaskRecord的状态来启用/禁用对应按钮(比如预处理完成后,训练按钮才可用)

示例模型代码:

# your_app/models.py
from django.db import models

class TaskRecord(models.Model):
    document_path = models.CharField(max_length=255)
    preprocessed_data_path = models.CharField(max_length=255, blank=True)
    trained_model_path = models.CharField(max_length=255, blank=True)
    final_result = models.JSONField(blank=True)
    status = models.CharField(max_length=50, default='INITIAL')
    
    STATUS_CHOICES = [
        ('INITIAL', '初始状态'),
        ('PREPROCESSING', '预处理中'),
        ('PREPROCESSED', '预处理完成'),
        ('TRAINING', '训练中'),
        ('SUCCESS', '全部完成'),
        ('FAILURE', '失败'),
    ]

每个任务执行时更新这个模型的状态,前端通过查询模型状态来控制按钮的可用性。


关键注意事项

  • 异步任务必须用Celery:同步视图处理耗时任务一定会超时,Celery能把任务放到后台执行,不阻塞请求。
  • 状态跟踪很重要:用户需要知道任务进度,所以一定要用update_state更新任务状态,前端轮询获取。
  • 清理临时文件:任务完成后记得删除上传的文档、中间预处理文件,避免占满服务器存储空间。
  • 错误捕获:在任务函数里加try-except块,捕获异常并更新状态,让用户知道哪里出了问题。

这样就能完美实现按钮触发多阶段任务的需求啦!

内容的提问来源于stack exchange,提问作者MustafaSalih

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.11 08:49:12