Json数据转换为ADO.NET DataSet其实方法有很多,Newtonsoft.Json也提供了DataSet的Converter用以转换Json数据。但是有些情况下DataSet Converter并不管用,而且也不一定能够满足项目需要。这里介绍另一种简单有效的方法,能够方便快速地将Json数据转为ADO.NET DataSet。
设计
事实上Newtonsoft.Json已经提供了一套完整的Json数据文档结构,Newtonsoft.Json.Linq命名空间下提供了这种文档结构的对象模型,因此我们可以借用这样的模型,在其上应用访问者(Visitor,GoF95)模式,对树状结构的对象模型进行遍历,以达到ADO.NET DataTable、DataRelation的创建以及DataSet的生成。基本对象模型如下:
其实实现起来还是非常简单的,我已经把完整的项目和单元测试开源到GitHub上。具体的代码可以参考https://github.com/daxnet/Json2DataSet开源项目。
性能
性能方面,在实现的过程中,我发现有两个地方是性能瓶颈:
- 正则表达式
- JToken.Path属性
如果在你的代码中需要高频率地反复调用这两种操作,那么你就需要考虑性能问题。尤其是JToken.Path属性,它的内部实现牵涉到链表数据结构、复杂循环等,因此效率不是很高,应该尽量避免使用这一属性(当然我开源的代码中还有一处在调用该属性,可以进一步优化)。
另一方面,对于ADO.NET DataTable和DataRelation的构建,性能还是相当高的,无需担心。总体上看,将15MB的Json数据转换为DataSet仅需4秒左右,有兴趣的朋友还可以在该代码基础上进一步优化。
调用
在该开源项目主页上已经说明了调用方式。很简单:
var json = File.ReadAllText(@"d:\test.json");var dataSet = Json2DataSetConverter.Convert(json);
比如通过调用某个RESTful API,获得Json Response以后,直接将返回结果转换为DataSet,并在Visual Studio Debug Visualizer for DataSet中看到某公司的客户信息,以及这些客户所完成的订单数据:
应用
TIBCO Spotfire是一种世界先进的数据分析软件,不仅功能强大,还可以为其定制数据导入插件,方便地将外部数据导入其中进行分析。它是以表的形式对数据进行整合和分析的,因此,它对ADO.NET DataSet的支持是非常好的,能够很方便地将ADO.NET DataSet中所包含的表数据导入。
现有一个RESTful API,它能够获取全世界所有国家的列表信息,包括国家名称、语言、人口、与该国接壤的国家数量等等。该API的地址是:
GET http://restcountries.eu/rest/v1/all好了,现在我开发了一个非常简单的插件,可以通过GET命令,从RESTful API导入数据到TIBCO Spotfire中:
导入数据后,我可以立刻分析出哪个国家人口比重最大,哪个国家与其接壤的国家数量最多:
看,我国不仅人口最多(占世界人口的19%),而且与我国接壤的国家数量最多(15个)。
本文链接:将Json数据转换为ADO.NET DataSet对象,转载请注明。
英文博客地址:http://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-v-user-logins
中文翻译地址:http://www.pythondoc.com/flask-mega-tutorial/userlogin.html
开源中国社区:http://www.oschina.net/translate/the-flask-mega-tutorial-part-v-user-logins
备注:我是三个一起看的,有些部分的中文翻译太拗口而且还有错,因此我选择是比较清晰的中文解释,而有些部分是直接翻译英文博客。
上一部分:Flask学习之四 数据库
一、配置
对于登录系统,我们将会使用到两个扩展,Flask-Login 和 Flask-OpenID。配置情况如下(文件 app__init__.py):
from flask.ext.login import LoginManager
from flask.ext.openid import OpenID
from config import basedir
lm = LoginManager()
lm.init_app(app)
oid = OpenID(app, os.path.join(basedir, 'tmp'))
Flask-OpenID 扩展需要一个存储文件的临时文件夹的路径。对此,我们提供了一个 tmp 文件夹的路径。
二、重构用户模型
Flask-Login扩展需要在我们的User类里实现一些方法。
为 Flask-Login 实现的 User 类(文件 app/models.py):
id = db.Column(db.Integer, primary_key = True)
nickname = db.Column(db.String(64), unique = True)
email = db.Column(db.String(120), unique = True)
role = db.Column(db.SmallInteger, default = ROLE_USER)
posts = db.relationship('Post', backref = 'author', lazy = 'dynamic')
def is_authenticated(self):
return True
def is_active(self):
return True
def is_anonymous(self):
return False
def get_id(self):
return unicode(self.id)
def __repr__(self):
return '<User %r>' % (self.nickname)
is_authenticated 方法:一般而言,这个方法应该只返回 True,除非表示用户的对象因为某些原因不允许被认证。
is_active 方法:应该返回 True,除非用户是无效的,比如他们的账号被禁止。
is_anonymous方法:为那些不被获准登录的用户返回True。
get_id方法:为用户返回唯一的unicode标识符。我们用数据库层生成唯一的id。
三、User loader 回调
现在我们通过使用Flask-Login和Flask-OpenID扩展来实现登录系统
首先,我们需要写一个方法从数据库加载到一个用户。这个方法会被Flask-Login使用(文件 app/views.py):
def load_user(id):
return User.query.get(int(id))
备注:其实我现在对python中的@符号的用法还是不甚明了。
注意在 Flask-Login 中的用户 ids 永远是 unicode 字符串,因此在我们把 id 发送给 Flask-SQLAlchemy 之前,需要把 id 转成整型,否则会报错!
四、登录视图函数
接着更新登录视图函数(文件 app/views.py):
from flask.ext.login import login_user, logout_user, current_user, login_required
from app import app, db, lm, oid
from forms import LoginForm
from models import User
@app.route('/login', methods=['GET', 'POST'])
@oid.loginhandler
def login():
if g.user is not None and g.user.is_authenticated():
return redirect(url_for('index'))
form = LoginForm()
if form.validate_on_submit():
session['remember_me'] = form.remember_me.data
return oid.try_login(form.openid.data, ask_for=['nickname', 'email'])
return render_template('login.html',
title='Sign In',
form=form,
providers=app.config['OPENID_PROVIDERS'])
注意上面导入了很多新模块,之后会用到。
视图函数添加了一个新的装饰器:oid.loginhandler。它告诉Flask-OpenID这是我们的登录视图函数。
在函数开始的时候我们就检查 g.user 是不是一个已经认证的用户,如果已经认证就直接跳转到主页面,避免二次登录。
Flask 中的 g 全局变量是一个在请求生命周期中用来存储和共享数据。登录的用户存储在这里(g)。
我们在调用redirect()时使用的url_for()方法是Flask定义的从给定的view方法获取url。如果你想重定向到index页面,你很可能使用redirect('/index'),但是让Flask为你构造url是有好处的。见 http://dormousehole.readthedocs.org/en/latest/quickstart.html#url
当我们从登录表单得到返回数据,接下来要运行的代码也是新写的。这儿我们做两件事。首先我们保存remember_me的布尔值到Flask的 session中,别和Flask-SQLAlchemy的db.session混淆了。之前我们已经知道 flask.g 对象在请求整个生命周期中存储和共享数据。flask.session 提供了一个更加复杂的服务对于存储和共享数据。一旦数据存储在会话对象中,在来自同一客户端的现在和任何以后的请求都是可用的。数据将保持在session中直到被明确的移除。为了做到这些,Flask为每个客户端建立各自的 session。
oid.try_login通过Flask-OpenID来执行用户认证。该函数有两个参数,用户在 web 表单提供的 openid 以及我们从 OpenID 提供商得到的数据项列表。因为我们已经在用户模型类中定义了 nickname 和 email,这也是我们将要从 OpenID 提供商索取的。
基于OpenID的认证是异步的。如果认证成功,Flask-OpenID将调用有由oid.after_login装饰器注册的方法。如果认证失败那么用户会被重?p>阅读更多内容
没有评论:
发表评论