Django定时任务多线程调用报dict object is not callable问题咨询
问题根因与解决方案
1. 报错TypeError: dict object is not callable的直接原因
你给threading.Thread的target参数传入的是已经执行完成的函数返回结果,而不是函数本身:
# 错误写法:此处会先执行book_english(email, full_name),拿到返回的字典传给target threading.Thread(target=book_english(email, full_name))
线程启动时会尝试调用target指向的对象,此时target是字典,自然会抛出「dict不可调用」的错误,和函数有没有返回值没有任何关系。
关于线程目标函数返回值的问题
- 线程目标函数允许有返回值,默认情况下返回值会被线程对象回收,不会直接向外抛出,也完全不会影响其他线程的正常运行
- 如果需要获取线程返回值,可以通过继承
Thread类重写run方法、使用concurrent.futures.ThreadPoolExecutor、或者传入可变对象(比如列表、字典)存储结果的方式实现
2. 全问题修复方案
2.1 修正线程传参的错误写法
Thread类提供了args参数用来传递目标函数需要的位置参数,正确写法如下:
# 英文订票线程写法 myThread = threading.Thread(target=book_english, args=(email, full_name)) # 意大利文订票线程写法 myThread = threading.Thread(target=book_italian, args=(email, full_name, gender))
2.2 修正循环取值的逻辑错误
你的代码里遍历tickets得到单条记录ticket,但后续取值全用了tickets['xxx'](整个列表)而非ticket['xxx'],还有email = tickets[email]里的key没有加引号,属于语法错误,修正后:
def ticket_booking(): query = " SELECT * FROM vw_ticket_list;" ttd = [] try: result = query_to_dicts(query) tickets = json.loads(to_json(result)) if tickets: for ticket in tickets: # 修正为从单条ticket取值,key加引号 full_name = ticket['full_name'] gender = ticket['gender'] email = ticket['email'] if ticket['language_id'] == 1: myThread = threading.Thread(target=book_english, args=(email, full_name)) myThread.start() myThread.join() elif ticket['language_id'] == 2: myThread = threading.Thread(target=book_italian, args=(email, full_name, gender)) myThread.start() myThread.join() except Exception as e: # 建议增加异常日志打印,方便排查问题 print(f"任务执行出错:{str(e)}")
另外你提供的book_italian函数存在语法错误,try后需要加冒号,return语句也需要修正为标准Python写法,避免运行时报错。
2.3 crontab无法正常运行的排查点
- 确认crontab执行的Python环境和项目虚拟环境一致,需要写全Python解释器的绝对路径,比如
/data/your_project/venv/bin/python /data/your_project/manage.py your_custom_command - 确认Django定时任务的调用方式正确,如果是自定义管理命令,需要先在对应app下创建
management/commands目录,实现符合规范的命令类 - 给任务增加日志输出,所有异常都写入本地日志文件,避免crontab运行时无报错信息可查
2.4 额外优化建议
你现在每个线程启动后立刻调用join(),相当于还是串行执行,完全没有用到多线程的优势,如果需要并发执行,可以先启动所有线程,再统一调用join:
threads = [] for ticket in tickets: # 省略取值逻辑 if ticket['language_id'] ==1: t = threading.Thread(target=book_english, args=(email, full_name)) else: t = threading.Thread(target=book_italian, args=(email, full_name, gender)) threads.append(t) t.start() # 等待所有线程执行完成 for t in threads: t.join()
内容的提问来源于stack exchange,提问作者user11717481
相关产品推荐
相关产品推荐

