# -*- encoding: utf8 -*-
# version 1.11 import tkinter.messagebox,os
from tkinter import *
from tkinter.ttk import *
from tkinter import Menu
import datetime
import threading
import pickle
import time
import tushare as ts
import pywinauto
import pywinauto.clipboard
import pywinauto.application
NUM_OF_STOCKS = 5 # 自定义股票数量
is_start = False
is_monitor = True
set_stocks_info = []
actual_stocks_info = []
consignation_info = []
is_ordered = [1] * NUM_OF_STOCKS # 1:未下单 0:已下单
is_dealt = [0] * NUM_OF_STOCKS # 0: 未成交 负整数:卖出数量, 正整数:买入数量
stock_codes = [''] * NUM_OF_STOCKS class OperationThs:
def __init__(self):
try:
self.__app = pywinauto.application.Application()
self.__app.connect(title='网上股票交易系统5.0')
top_hwnd = pywinauto.findwindows.find_window(title='网上股票交易系统5.0')
dialog_hwnd = pywinauto.findwindows.find_windows(top_level_only=False, class_name='#32770', parent=top_hwnd)[0]
wanted_hwnds = pywinauto.findwindows.find_windows(top_level_only=False, parent=dialog_hwnd)
print('wanted_hwnds length', len(wanted_hwnds))
if len(wanted_hwnds) not in (99,97,96,98,100,101):
tkinter.messagebox.showerror('错误', '无法获得“同花顺双向委托界面”的窗口句柄,请将同花顺交易系统切换到“双向委托界面”!')
exit()
self.__main_window = self.__app.window_(handle=top_hwnd)
self.__dialog_window = self.__app.window_(handle=dialog_hwnd)
except:
pass
def __buy(self, code, quantity):
"""买函数
:param code: 代码, 字符串
:param quantity: 数量, 字符串
"""
self.__dialog_window.Edit1.SetFocus()
time.sleep(0.2)
self.__dialog_window.Edit1.SetEditText(code)
time.sleep(0.2)
if quantity != '':
self.__dialog_window.Edit3.SetEditText(quantity)
time.sleep(0.2)
self.__dialog_window.Button1.Click()
time.sleep(0.2)
def __sell(self, code, quantity):
"""
卖函数
:param code: 股票代码, 字符串
:param quantity: 数量, 字符串
"""
self.__dialog_window.Edit4.SetFocus()
time.sleep(0.2)
self.__dialog_window.Edit4.SetEditText(code)
time.sleep(0.2)
if quantity != '':
self.__dialog_window.Edit6.SetEditText(quantity)
time.sleep(0.2)
self.__dialog_window.Button2.Click()
time.sleep(0.2)
def __closePopupWindow(self):
"""
关闭一个弹窗。
:return: 如果有弹出式对话框,返回True,否则返回False
"""
popup_hwnd = self.__main_window.PopupWindow()
if popup_hwnd:
popup_window = self.__app.window_(handle=popup_hwnd)
popup_window.SetFocus()
popup_window.Button.Click()
return True
return False def __closePopupWindows(self):
"""
关闭多个弹出窗口
:return:
"""
while self.__closePopupWindow():
time.sleep(0.5)
def order(self, code, direction, quantity):
"""
下单函数
:param code: 股票代码, 字符串
:param direction: 买卖方向, 字符串
:param quantity: 买卖数量, 字符串
"""
if direction == 'B':
self.__buy(code, quantity)
if direction == 'S':
self.__sell(code, quantity)
self.__closePopupWindows()
def maxWindow(self):
"""
最大化窗口
"""
if self.__main_window.GetShowState() != 3: self.__main_window.Maximize()
self.__main_window.SetFocus() def minWindow(self):
"""
最小化窗体
"""
if self.__main_window.GetShowState() != 2:
self.__main_window.Minimize() def refresh(self, t=0.5):
"""
点击刷新按钮
:param t:刷新后的等待时间
"""
self.__dialog_window.Button5.Click()
time.sleep(t)
def getMoney(self):
"""
获取可用资金
"""
return float(self.__dialog_window.Static19.WindowText())
@staticmethod
def __cleanClipboardData(data, cols=11):
"""
清洗剪贴板数据
:param data: 数据
:param cols: 列数
:return: 清洗后的数据,返回列表
"""
lst = data.strip().split()[:-1]
matrix = []
for i in range(0, len(lst) // cols):
matrix.append(lst[i * cols:(i + 1) * cols])
return matrix[1:] def __copyToClipboard(self):
"""
拷贝持仓信息至剪贴板
:return:
"""
self.__dialog_window.CVirtualGridCtrl.RightClick(coords=(30, 30))
self.__main_window.TypeKeys('C') def __getCleanedData(self):
"""
读取ListView中的信息
:return: 清洗后的数据
"""
self.__copyToClipboard()
data = pywinauto.clipboard.GetData()
return self.__cleanClipboardData(data) def __selectWindow(self, choice):
"""
选择tab窗口信息
:param choice: 选择个标签页。持仓,撤单,委托,成交
:return:
"""
rect = self.__dialog_window.CCustomTabCtrl.ClientRect()
x = rect.width() // 8
y = rect.height() // 2
if choice == 'W':
x = x
elif choice == 'E':
x *= 3
elif choice == 'R':
x *= 5
elif choice == 'A':
x *= 7
self.__dialog_window.CCustomTabCtrl.ClickInput(coords=(x, y))
time.sleep(0.5) def __getInfo(self, choice):
"""
获取股票信息
"""
self.__selectWindow(choice=choice)
return self.__getCleanedData() def getPosition(self):
"""
获取持仓
:return:
"""
return self.__getInfo(choice='W')
@staticmethod
def getDeal(code, pre_position, cur_position):
"""
获取成交数量
:param code: 需检查的股票代码, 字符串
:param pre_position: 下单前的持仓
:param cur_position: 下单后的持仓
:return: 0-未成交, 正整数是买入的数量, 负整数是卖出的数量
"""
if pre_position == cur_position:
return 0
pre_len = len(pre_position)
cur_len = len(cur_position)
if pre_len == cur_len:
for row in range(cur_len):
if cur_position[row][0] == code:
return int(float(cur_position[row][1]) - float(pre_position[row][1]))
if cur_len > pre_len:
return int(float(cur_position[-1][1])) def withdraw(self, code, direction):
"""
指定撤单
:param code: 股票代码
:param direction: 方向 B, S
:return:
"""
row_pos = []
info = self.__getInfo(choice='R')
if direction == 'B':
direction = '买入'
elif direction == 'S':
direction = '卖出'
if info:
for index, element in enumerate(info):
if element[0] == code:
if element[1] == direction:
row_pos.append(index)
if row_pos:
for row in row_pos:
self.__dialog_window.CVirtualGridCtrl.ClickInput(coords=(7, 28 + 16 * row))
self.__dialog_window.Button12.Click()
self.__closePopupWindows() def withdrawBuy(self):
"""
撤买
:return:
"""
self.__selectWindow(choice='R')
self.__dialog_window.Button8.Click()
self.__closePopupWindows() def withdrawSell(self):
"""
撤卖
:return:
"""
self.__selectWindow(choice='R')
self.__dialog_window.Button9.Click()
self.__closePopupWindows() def withdrawAll(self):
"""
全撤
:return:
"""
self.__selectWindow(choice='R')
self.__dialog_window.Button7.Click()
self.__closePopupWindows() def getStockData():
"""
获取股票实时数据
:return:股票实时数据
"""
global stock_codes
code_name_price = []
try:
df = ts.get_realtime_quotes(stock_codes)
df_len = len(df)
for stock_code in stock_codes:
is_found = False
for i in range(df_len):
actual_code = df['code'][i]
if stock_code == actual_code:
code_name_price.append((actual_code, df['name'][i], float(df['price'][i])))
is_found = True
break
if is_found is False:
code_name_price.append(('', '', 0))
except:
code_name_price = [('', '', 0)] * NUM_OF_STOCKS # 网络不行,返回空
return code_name_price
def monitor():
"""
实时监控函数
"""
global actual_stocks_info, consignation_info, is_ordered, is_dealt, set_stocks_info
count = 1
pre_position = []
try:
operation = OperationThs()
operation.maxWindow()
pre_position = operation.getPosition()
# print(pre_position)
while is_monitor:
if is_start:
actual_stocks_info = getStockData()
for row, (actual_code, actual_name, actual_price) in enumerate(actual_stocks_info):
if actual_code and is_start and is_ordered[row] == 1 and actual_price > 0 \
and set_stocks_info[row][1] and set_stocks_info[row][2] > 0 \
and set_stocks_info[row][3] and set_stocks_info[row][4] \
and datetime.datetime.now().time() > set_stocks_info[row][5]:
if (set_stocks_info[row][1] == '>' and actual_price > set_stocks_info[row][2]) or \
(set_stocks_info[row][1] == '<' and float(actual_price) < set_stocks_info[row][2]):
operation.maxWindow()
operation.order(actual_code, set_stocks_info[row][3], set_stocks_info[row][4])
dt = datetime.datetime.now()
is_ordered[row] = 0
operation.refresh()
cur_position = operation.getPosition()
is_dealt[row] = operation.getDeal(actual_code, pre_position, cur_position)
consignation_info.append(
(dt.strftime('%x'), dt.strftime('%X'), actual_code,
actual_name, set_stocks_info[row][3],
actual_price, set_stocks_info[row][4], '已委托', is_dealt[row]))
pre_position = cur_position
if count % 200 == 0:
operation.refresh()
time.sleep(3)
count += 1 except:
tkinter.messagebox.showerror('错误', '请先打开“同花顺双向委托界面”后在打开自动交易系统!')
sys.exit() class StockGui:
global is_monitor
def __init__(self):
self.window = Tk()
self.window.title("自动化交易系统-同花顺")
# 左上角图标
self.window.iconbitmap('e:\ico.ico')
self.window.resizable(0, 0)
frame1 = Frame(self.window)
frame1.pack(padx=10, pady=10)
Label(frame1, text="股票代码", width=8, justify=CENTER).grid(
row=1, column=1, padx=5, pady=5)
Label(frame1, text="股票名称", width=8, justify=CENTER).grid(
row=1, column=2, padx=5, pady=5)
Label(frame1, text="实时价格", width=8, justify=CENTER).grid(
row=1, column=3, padx=5, pady=5)
Label(frame1, text="关系", width=4, justify=CENTER).grid(
row=1, column=4, padx=5, pady=5)
Label(frame1, text="设定价格", width=8, justify=CENTER).grid(
row=1, column=5, padx=5, pady=5)
Label(frame1, text="方向", width=4, justify=CENTER).grid(
row=1, column=6, padx=5, pady=5)
Label(frame1, text="数量", width=8, justify=CENTER).grid(
row=1, column=7, padx=5, pady=5)
Label(frame1, text="时间可选", width=8, justify=CENTER).grid(
row=1, column=8, padx=5, pady=5)
Label(frame1, text="委托", width=6, justify=CENTER).grid(
row=1, column=9, padx=5, pady=5)
Label(frame1, text="成交", width=6, justify=CENTER).grid(
row=1, column=10, padx=5, pady=5)
self.rows = NUM_OF_STOCKS
self.cols = 10
self.variable = []
for row in range(self.rows):
self.variable.append([])
for col in range(self.cols):
self.variable[row].append(StringVar())
for row in range(self.rows):
Entry(frame1, textvariable=self.variable[row][0],
width=8).grid(row=row + 2, column=1, padx=5, pady=5)
Entry(frame1, textvariable=self.variable[row][1], state=DISABLED,
width=8).grid(row=row + 2, column=2, padx=5, pady=5)
Entry(frame1, textvariable=self.variable[row][2], state=DISABLED, justify=RIGHT,
width=8).grid(row=row + 2, column=3, padx=5, pady=5)
Combobox(frame1, values=('<', '>'), textvariable=self.variable[row][3],
width=2).grid(row=row + 2, column=4, padx=5, pady=5)
Spinbox(frame1, from_=0, to=999, textvariable=self.variable[row][4], justify=RIGHT,
increment=0.01, width=6).grid(row=row + 2, column=5, padx=5, pady=5)
Combobox(frame1, values=('B', 'S'), textvariable=self.variable[row][5],
width=2).grid(row=row + 2, column=6, padx=5, pady=5)
Spinbox(frame1, from_=0, to=10000, textvariable=self.variable[row][6], justify=RIGHT,
increment=100, width=6).grid(row=row + 2, column=7, padx=5, pady=5)
Entry(frame1, textvariable=self.variable[row][7],
width=8).grid(row=row + 2, column=8, padx=5, pady=5)
Entry(frame1, textvariable=self.variable[row][8], state=DISABLED, justify=CENTER,
width=6).grid(row=row + 2, column=9, padx=5, pady=5)
Entry(frame1, textvariable=self.variable[row][9], state=DISABLED, justify=RIGHT,
width=6).grid(row=row + 2, column=10, padx=5, pady=5) frame3 = Frame(self.window)
frame3.pack(padx=10, pady=10)
# 创建菜单功能
self.menuBar = Menu(self.window)
self.window.config(menu=self.menuBar)
# tearoff=0 代表将菜单项最上面的一条虚线去掉,默认是存在的
self.fileMenu = Menu(self.menuBar,tearoff=0)
# 创建一个名为“帮助”的菜单项
self.menuBar.add_cascade(label="帮助",menu=self.fileMenu)
# 在“帮助”项下添加一个名为“关于”的选项
self.fileMenu.add_command(label="关于",command =self.about)
# 增加一条横线
self.fileMenu.add_separator()
# 在“帮助”项下添加一个名为“退出”的选项,并绑定执行函数
self.fileMenu.add_command(label="退出",command=self.close)
# 增加第二个导航栏
# self.helpMenu = Menu(self.menuBar,tearoff=0)
# self.menuBar.add_cascade(label="Help", menu=self.helpMenu)
# self.helpMenu.add_command(label="About")
self.start_bt = Button(frame3, text="开始", command=self.start)
self.start_bt.pack(side=LEFT)
self.set_bt = Button(frame3, text='重置买卖', command=self.setFlags)
self.set_bt.pack(side=LEFT)
Button(frame3, text="历史记录", command=self.displayHisRecords).pack(side=LEFT)
Button(frame3, text='保存', command=self.save).pack(side=LEFT)
self.load_bt = Button(frame3, text='载入', command=self.load)
self.load_bt.pack(side=LEFT)
self.window.protocol(name="WM_DELETE_WINDOW", func=self.close)
self.window.after(100, self.updateControls)
self.window.mainloop() def displayHisRecords(self):
"""
显示历史信息
"""
global consignation_info
tp = Toplevel()
tp.title('历史记录')
tp.iconbitmap('e:\ico.ico')
tp.resizable(0, 1)
scrollbar = Scrollbar(tp)
scrollbar.pack(side=RIGHT, fill=Y)
col_name = ['日期', '时间', '证券代码', '证券名称', '方向', '价格', '数量', '委托', '成交']
tree = Treeview(
tp, show='headings', columns=col_name, height=30, yscrollcommand=scrollbar.set)
tree.pack(expand=1, fill=Y)
scrollbar.config(command=tree.yview)
for name in col_name:
tree.heading(name, text=name)
tree.column(name, width=70, anchor=CENTER) for msg in consignation_info:
tree.insert('', 0, values=msg)
def save(self):
"""
保存设置
"""
global set_stocks_info, consignation_info
self.getItems()
with open('stockInfo.dat', 'wb') as fp:
pickle.dump(set_stocks_info, fp)
pickle.dump(consignation_info, fp)
def load(self):
"""
载入设置
"""
global set_stocks_info, consignation_info
try:
with open('stockInfo.dat', 'rb') as fp:
set_stocks_info = pickle.load(fp)
consignation_info = pickle.load(fp)
for row in range(self.rows):
for col in range(self.cols):
if col == 0:
self.variable[row][col].set(set_stocks_info[row][0])
elif col == 3:
self.variable[row][col].set(set_stocks_info[row][1])
elif col == 4:
self.variable[row][col].set(set_stocks_info[row][2])
elif col == 5:
self.variable[row][col].set(set_stocks_info[row][3])
elif col == 6:
self.variable[row][col].set(set_stocks_info[row][4])
elif col == 7:
temp = set_stocks_info[row][5].strftime('%X')
if temp == '01:00:00':
self.variable[row][col].set('')
else:
self.variable[row][col].set(temp)
except Exception :
tkinter.messagebox.showerror('错误', "没有找到配置保存文件,请先进行股票买卖配置信息保存!")
def setFlags(self):
"""
重置买卖标志
"""
global is_start, is_ordered
if is_start is False:
is_ordered = [1] * NUM_OF_STOCKS
tkinter.messagebox.showinfo('重置成功', "重置成功!")
def updateControls(self):
"""
实时股票名称、价格、状态信息
"""
global actual_stocks_info, is_start
if is_start:
for row, (actual_code, actual_name, actual_price) in enumerate(actual_stocks_info):
if actual_code:
self.variable[row][1].set(actual_name)
self.variable[row][2].set(str(actual_price))
if is_ordered[row] == 1:
self.variable[row][8].set('监控中')
elif is_ordered[row] == 0:
self.variable[row][8].set('已委托')
self.variable[row][9].set(str(is_dealt[row]))
else:
self.variable[row][1].set('')
self.variable[row][2].set('')
self.variable[row][8].set('')
self.variable[row][9].set('')
self.window.after(3000, self.updateControls)
@staticmethod
def __pickCodeFromItems(items_info):
"""
提取股票代码
:param items_info: UI下各项输入信息
:return:股票代码列表
"""
stock_codes = []
for item in items_info:
stock_codes.append(item[0])
return stock_codes def start(self):
"""
启动停止
"""
global is_start, stock_codes, set_stocks_info
if is_start is False:
is_start = True
else:
is_start = False if is_start:
self.getItems()
stock_codes = self.__pickCodeFromItems(set_stocks_info)
self.start_bt['text'] = '停止'
self.set_bt['state'] = DISABLED
self.load_bt['state'] = DISABLED
tkinter.messagebox.showinfo('成功','启动成功!')
else:
self.start_bt['text'] = '开始'
self.set_bt['state'] = NORMAL
self.load_bt['state'] = NORMAL
def about(self):
tkinter.messagebox.showinfo("关于",'\r此系统仅适应于同花顺网上交易5.0,使用时请先登陆同花顺网上交易系统并切换到“同花顺双向委托界面”。\r 版本号:v 1.0.0 \r 作者:水域\r 发布日期:2017.01.11')
def close(self):
"""
关闭程序时,停止monitor线程
"""
global is_monitor
is_monitor = False
self.window.quit() def getItems(self):
"""
获取UI上用户输入的各项数据,
"""
global set_stocks_info
set_stocks_info = []
# 获取买卖价格数量输入项等
for row in range(self.rows):
set_stocks_info.append([])
for col in range(self.cols):
temp = self.variable[row][col].get().strip()
if col == 0:
if len(temp) == 6 and temp.isdigit(): # 判断股票代码是否为6位数
set_stocks_info[row].append(temp)
else:
set_stocks_info[row].append('')
elif col == 3:
if temp in ('>', '<'):
set_stocks_info[row].append(temp)
else:
set_stocks_info[row].append('')
elif col == 4:
try:
price = float(temp)
if price > 0:
set_stocks_info[row].append(price) # 把价格转为数字
else:
set_stocks_info[row].append(0)
except ValueError:
set_stocks_info[row].append(0)
elif col == 5:
if temp in ('B', 'S'):
set_stocks_info[row].append(temp)
else:
set_stocks_info[row].append('')
elif col == 6:
if temp.isdigit() and int(temp) >= 0:
set_stocks_info[row].append(str(int(temp) // 100 * 100))
else:
set_stocks_info[row].append('')
elif col == 7:
try:
set_stocks_info[row].append(datetime.datetime.strptime(temp, '%H:%M:%S').time())
except ValueError:
set_stocks_info[row].append(datetime.datetime.strptime('1:00:00', '%H:%M:%S').time()) if __name__ == '__main__':
# StockGui()
t1 = threading.Thread(target=StockGui)
t1.start()
t2 = threading.Thread(target=monitor)
t2.start()

利用python3.5 +TK 开发股票自动交易伴侣的更多相关文章

  1. CTP API开发期货自动交易平台概论

    题目比较小众,先介绍一下CTP. 综合交易平台CTP(Comprehensive Transaction Platform)是由上海期货信息技术有限公司(上海期货交易所的全资子公司)开发的期货交易平台 ...

  2. 转:【Python3网络爬虫开发实战】 requests基本用法

    1. 准备工作 在开始之前,请确保已经正确安装好了requests库.如果没有安装,可以参考1.2.1节安装. 2. 实例引入 urllib库中的urlopen()方法实际上是以GET方式请求网页,而 ...

  3. [Python] 利用Django进行Web开发系列(一)

    1 写在前面 在没有接触互联网这个行业的时候,我就一直很好奇网站是怎么构建的.现在虽然从事互联网相关的工作,但是也一直没有接触过Web开发之类的东西,但是兴趣终归还是要有的,而且是需要自己动手去实践的 ...

  4. [Python] 利用Django进行Web开发系列(二)

    1 编写第一个静态页面——Hello world页面 在上一篇博客<[Python] 利用Django进行Web开发系列(一)>中,我们创建了自己的目录mysite. Step1:创建视图 ...

  5. 跟我一起学WCF(2)——利用.NET Remoting技术开发分布式应用

    一.引言 上一篇博文分享了消息队列(MSMQ)技术来实现分布式应用,在这篇博文继续分享下.NET平台下另一种分布式技术——.NET Remoting. 二..NET Remoting 介绍 2.1 . ...

  6. 转载:如何利用Vim进行Erlang开发

    转自:http://ovalpo.info/how_to_use_vim_for_erlang_dev/ 如何利用Vim进行Erlang开发 by Martin J. Logan on Septemb ...

  7. 【工具篇】利用DBExportDoc V1.0 For MySQL自动生成数据库表结构文档

    对于DBA或开发来说,如何规范化你的数据库表结构文档是灰常之重要的一件事情.但是当你的库,你的表排山倒海滴多的时候,你就会很头疼了. 推荐一款工具DBExportDoc V1.0 For MySQL( ...

  8. 利用connect建立前端开发服务器

    利用connect建立前端开发服务器 对于前后端完全分离的系统,开发时候我们需要给前端配置服务器,当然我们可以选择Nginx之类的服务器进行配置,但我们也能使用NodeJS构建高自由度的前端开发服务器 ...

  9. 利用Bootstrap+Avalonjs+EntityFramework 开发ASP.NET WebForm应用程序(上)

    本文将介绍如何利用Bootstrap+Avalonjs+EntityFramework 开发ASP.NET WebForm应用程序,分为上下两篇.上篇主要介绍实现,下篇主要介绍界面. 打开Visual ...

随机推荐

  1. Android Recovery模式学习体会

        最近在学习Android的Recovery模式,感觉它和Windows的安全模式很相似.两者的工作原理都是只加载少量的系统组件(内核是必须的),使系统运行在最小模式,这样就可以在不影响当前系统 ...

  2. [转]A Faster UIWebView Communication Mechanism

    ref:http://blog.persistent.info/2013/10/a-faster-uiwebview-communication.html Use location.hash or t ...

  3. js闭包和ie内存泄露原理

    也议 js闭包和ie内存泄露原理 可以, 但小心使用. 闭包也许是 JS 中最有用的特性了. 有一份比较好的介绍闭包原理的文档. 有一点需要牢记, 闭包保留了一个指向它封闭作用域的指针, 所以, 在给 ...

  4. URL 调度器(URL dispatcher)

    URL 调度器(URL dispatcher) 在刚开始接触 django 的时候, 我们尝试着从各种入门文档中创建一个自己的 django 项目, 需要在 mysite.urls.py 中配置 UR ...

  5. iOS 7用户界面过渡指南

    iOS 7用户界面过渡指南 泽涛陈 | 交互设计 视觉设计 译译生辉 | 2013.06.26 本文最新PDF格式文档下载: http://vdisk.weibo.com/s/InBpB(2013年7 ...

  6. 学习SQL关联查询

    通过一个小问题来学习SQL关联查询 原话题: 是关于一个left join的,没有技术难度,但不想清楚不一定能回答出正确答案来: TabA表有三个字段Id,Col1,Col2 且里面有一条数据1,1, ...

  7. PrintWriter返回值乱码问题

    ⑴response.setCharacterEncoding("utf-8"); ⑵response.setContentType("text/html; charset ...

  8. asp.net mvc Route 使用自定义条件(constraints)禁止某ip登陆

    asp.net mvc Route 使用自定义条件(constraints)禁止某ip登陆 前言 本文的目的是利用Mvc route创建一个自定义约束来控制路由跳转实现禁止ip登陆,当然例子可能不合理 ...

  9. Easyui + asp.net MVC 系列教程 完成登录

    Easyui + asp.net MVC 系列教程 第09-17 节 完成登录 高清录制 前面八节 在这里 Easyui + asp.net mvc + sqlite 开发教程(录屏)适合入门 在接下 ...

  10. tornado with MySQL, torndb, django model, SQLAlchemy ==> JSON dumped

    现在,我们用torndo做web开发框架,用他内部机制来处理HTTP请求.传说中的非阻塞式服务. 整来整去,可谓之一波三折.可是,无论怎么样,算是被我做成功了. 在tornado服务上,采用三种数据库 ...