阶段总结一:数据库篇

p,li { white-space: pre-wrap }

最近一直在用python的Flask框架开发应用。相比bottle框架,Flask丰富的扩展让代码写起来更加方便。在边踩坑边学习中得到了一些总结。比较杂,也算是定期的阶段总结吧,

一:初识Flask-SQLAlchmey

p,li { white-space: pre-wrap }

假设有一个如下的数据表(数据库为pgsql)

--学生表
CREATE TABLE students
(
  id serial primary key,
  name varchar(20),
  mobileno varchar(11),
  email varchar(32),
  address varchar(100)
);
--爱好表
CREATE TABLE hobby
(
  id serial primary key,
  students_id integer references students (id),
  name varchar(20)
);
--朋友表
CREATE TABLE friends
(
  id serial primary key,
  frends_id integer references students (id),
  friended_id integer references students (id)
);
--插入数据
INSERT INTO students (name, mobileno, email, address) VALUES (‘小王‘, ‘13511111111‘, ‘[email protected]‘, ‘北京‘),(‘小李‘, ‘13522222222‘, ‘[email protected]‘, ‘上海‘),(‘小张‘, ‘13533333333‘, ‘[email protected]‘, ‘天津‘),(‘小徐‘, ‘13544444444‘, ‘[email protected]‘, ‘河北‘);
INSERT INTO hobby (students_id, name) VALUES (1, ‘唱歌‘),(1, ‘跳舞‘),(2, ‘跳舞‘),(2, ‘足球‘),(2, ‘篮球‘),(3, ‘唱歌‘),(3, ‘篮球‘),(3, ‘乒乓球‘),(4, ‘羽毛球‘),(4, ‘篮球‘),(4, ‘画画‘);
INSERT INTO friends (frends_id, friended_id) VALUES (1, 2),(1, 3),(1, 4),(2, 1),(2, 3),(2, 4),(3, 1),(4, 1),(4, 2);

p,li { white-space: pre-wrap }

想对应的模型类如下:

class Friends(db.Model):
    __tablename__ = ‘friends‘
    id = db.Column(db.Integer, primary_key=True)
    frends_id = db.Column(db.Integer, db.ForeignKey(‘students.id‘))
    friended_id = db.Column(db.Integer, db.ForeignKey(‘students.id‘))

class Students(db.Model):
    __tablename__ = ‘students‘
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(20))
    mobileno = db.Column(db.String(11))
    email = db.Column(db.String(32))
    address = db.Column(db.String(100))
    hobby = db.relationship(‘Hobby‘, backref=db.backref(‘students‘), lazy=‘dynamic‘)
    friended = db.relationship(‘Friends‘,
                              foreign_keys=[Friends.frends_id],
                               backref=db.backref(‘friends‘, lazy=‘joined‘),
                               lazy=‘dynamic‘,
                               cascade=‘all, delete-orphan‘)
    friends = db.relationship(‘Friends‘,
                              foreign_keys=[Friends.friended_id],
                              backref=db.backref(‘friended‘, lazy=‘joined‘),
                              lazy=‘dynamic‘,
                              cascade=‘all, delete-orphan‘)

    def __repr__(self):
        return ‘<Students %r>‘ % self.name

class Hobby(db.Model):
    __tablename__ = ‘hobby‘
    id = db.Column(db.Integer, primary_key=True)
    students_id = db.Column(db.Integer, db.ForeignKey(‘students.id‘))
    name = db.Column(db.String(20))

    def __repr__(self):
        return ‘<Hobby %r>‘ % self.name

p,li { white-space: pre-wrap }

使用Flask-SQLAlchmey处理时候,WEB没有问题,把结果集对象放到Jinja2模板中去解析,但是在给Android客户端返回数据时候便遇到了麻烦,参照了一些资料,发现大部分都是在表模型类中增加一个to_json的方法,如下

def to_json(demands):
        data =  [{
            "id": item.id,
            "content": item.content,
            "username": item.username,
            "city": item.city,
            "mobileno": hidmobile(item.mobileno),
            "tons": float(item.tons),
            "norm": item.norm,
            "faceurl": item.faceurl,
            "ctime": timestr(item.ctime)
        } for item in demands]
        return data

p,li { white-space: pre-wrap }

这样并不是很方便,因为这个方法可能在很多路由中被用到。如果是仅仅这一个表中的数据,通用行完全没有问题,但是对大型的数据处理来说,链表查询是经常会用到的。那么这里的字段便没法完全统一(因为可能会联不同的表,或者子查询).在搜索查阅时候发现一个方法(完美性有待进一步测试)

首先自定义一个json处理时候的类
class AlchemyEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj.__class__, DeclarativeMeta):
            fields = {}
            for jj in dir(obj):
                print jj
            for field in [x for x in dir(obj) if not x.startswith(‘_‘) and x != ‘metadata‘]:
                data = obj.__getattribute__(field)
                try:
                    json.dumps(data)     # this will fail on non-encodable values, like other classes
                    fields[field] = data
                except TypeError:    # 添加了对datetime的处理
                    if isinstance(data, datetime.datetime):
                        fields[field] = datetime.datetime.strftime(data, ‘%Y-%m-%d %H:%M:%S‘)   #data.isoformat()
                    elif isinstance(data, datetime.date):
                        fields[field] = datetime.datetime.strftime(data, ‘%Y-%m-%d‘)   #data.isoformat()
                    elif isinstance(data, datetime.timedelta):
                        fields[field] = (datetime.datetime.min + data).time().isoformat()
                    else:
                        fields[field] = None
            # a json-encodable dict
            return fields
        return json.JSONEncoder.default(self, obj)
  #使用
student = Students.query.all()
print student
return json.dumps(student, cls=AlchemyEncoder)

p,li { white-space: pre-wrap }

在使用中我发现,获取的结果中会比查询全表字段中多了2个字段(query, query_class)。但是并不影响使用。如果你还有更好的方法,请指教下。谢谢~

p,li { white-space: pre-wrap }

二:Flask-SQLAlchmey一些方法的使用

p,li { white-space: pre-wrap }

1,查询数据表中具体的字段, 在查询优化上,只查询需要的字段可以优化查询速度

p,li { white-space: pre-wrap }

第一种:query()方法

students = db.session.query(Students.name, Students.mobileno, Students.email)

p,li { white-space: pre-wrap }

第二种:with_entities()方法

Students.query.with_entities(Students.name, Students.mobileno, Students.email)

p,li { white-space: pre-wrap }

但是:使用第一种方法是无法再使用paginate()来分页查询的,因为paginate()方法只是Flask-SQLAlchemy的方法,而不是SQLAlchemy的方法,恰恰第一种方法使用的就是SQLAlchemy基类的方法

p,li { white-space: pre-wrap }

2,执行原生sql语句

sql = "UPDATE students SET name=:name, address=:address WHERE id=:id"
db.session.execute(sql, {"name": ‘王小明‘, "address": ‘北京丰台‘, "id":1})
db.session.commit()

p,li { white-space: pre-wrap }

当然SQLAlchemy的一些方法也是可用的,比如

from sqlalchemy import text
db.session.query("id","name", "mobile"
                        ).from_statement(
                                        text("SELECT id, name, mobileno AS mobile FROM students where name=:name")
                                        ).params(name=‘小张‘).all()

p,li { white-space: pre-wrap }

3,字段的别名

在联表查询时候,通常会给副表的字段设置一个别名,特别是主表和副表的字段相同时候,比如上面的hobby表和students表都有name字段,如果联表查询,就会出现问题,后来出现的字段会覆盖前面出现的字段.SQLAlchemy提供label()方法实现别名功能

data = Students.query.with_entities(Students.id, Students.name,
                                    Students.mobileno, Hobby.name.label(‘hobby_name‘)).join(Hobby).all()for i in data:
    print i.name, i.hobby_name

p,li { white-space: pre-wrap }

4,postgresql的array_to_string的用法

这个相当于python的list.split()方法,但是却有妙用;

p,li { white-space: pre-wrap }

场景:如上的students表和hobby表,一个学生有多个爱好(典型的一对多关系)。但是如何把这个学生和爱好合成一条记录展示呢,

首先想法就是取出所有的学生数据,然后循环,获取爱好数据,组合成一个字符串放到学生数据字典里。

但是使用array_to_string就可以使用一条sql语句搞定

select students.id, students.name, students.mobileno,array_to_string(array(SELECT name from hobby where hobby.students_id=students.id), ‘,‘) as hobbys  from students
1
小李

13522222222


跳舞,足球,篮球

2

小张

13533333333


唱歌,篮球,乒乓球

3

小徐

13544444444

羽毛球,篮球,画画

4

王小明

13511111111

唱歌,跳舞

p,li { white-space: pre-wrap }
p,li { white-space: pre-wrap }
p,li { white-space: pre-wrap }

时间: 2024-09-30 22:55:25

阶段总结一:数据库篇的相关文章

【基于WPF+OneNote+Oracle的中文图片识别系统阶段总结】之篇四:关于OneNote入库处理以及审核

篇一:WPF常用知识以及本项目设计总结:http://www.cnblogs.com/baiboy/p/wpf.html 篇二:基于OneNote难点突破和批量识别:http://www.cnblogs.com/baiboy/p/wpf1.html 篇三:批量处理后的txt文件入库处理:http://www.cnblogs.com/baiboy/p/wpf2.html 篇四:关于OneNote入库处理以及审核:http://www.cnblogs.com/baiboy/p/wpf3.html [

【基于WPF+OneNote+Oracle的中文图片识别系统阶段总结】之篇三:批量处理后的txt文件入库处理

篇一:WPF常用知识以及本项目设计总结:http://www.cnblogs.com/baiboy/p/wpf.html 篇二:基于OneNote难点突破和批量识别:http://www.cnblogs.com/baiboy/p/wpf1.html 篇三:批量处理后的txt文件入库处理:http://www.cnblogs.com/baiboy/p/wpf2.html 篇四:关于OneNote入库处理以及审核:http://www.cnblogs.com/baiboy/p/wpf3.html [

iOS开发数据库篇—FMDB数据库队列(下)

iOS开发数据库篇—FMDB数据库队列(下) 一.代码示例 1.需要先导入FMDB框架和头文件,由于该框架依赖于libsqlite库,所以还应该导入该库. 2.代码如下: 1 // 2 // YYViewController.m 3 // 05-FMDB数据库队列 4 // 5 // Created by apple on 14-7-28. 6 // Copyright (c) 2014年 wendingding. All rights reserved. 7 // 8 9 #import "Y

iOS开发数据库篇—SQLite的应用

iOS开发数据库篇—SQLite的应用 一.简单说明 在iOS中使用SQLite3,首先要添加库文件libsqlite3.dylib和导入主头文件. 导入头文件,可以使用库中的函数(是纯C语言的) 二.具体说明 新建一个项目,在项目的主界面中放四个按钮(分别是,增加.删除.修改.查询). 1.sqlite3_open(<#const char *filename#>, <#sqlite3 **ppDb#>)函数的一些说明: (1)作用:把一个文件名称传递给他,它会自动检测这个文件是

iOS开发数据库篇—FMDB简单介绍

iOS开发数据库篇—FMDB简单介绍 一.简单说明 1.什么是FMDB FMDB是iOS平台的SQLite数据库框架 FMDB以OC的方式封装了SQLite的C语言API 2.FMDB的优点 使用起来更加面向对象,省去了很多麻烦.冗余的C语言代码 对比苹果自带的Core Data框架,更加轻量级和灵活 提供了多线程安全的数据库操作方法,有效地防止数据混乱 3.FMDB的github地址 https://github.com/ccgus/fmdb 二.核心类 FMDB有三个主要的类 (1)FMDa

iOS开发数据库篇—FMDB数据库队列

iOS开发数据库篇—FMDB数据库队列 一.代码示例 1.需要先导入FMDB框架和头文件,由于该框架依赖于libsqlite库,所以还应该导入该库. 2.代码如下: 1 // 2 // YYViewController.m 3 // 05-FMDB数据库队列 4 // 5 // Created by apple on 14-7-28. 6 // Copyright (c) 2014年 wendingding. All rights reserved. 7 // 8 9 #import "YYVi

iOS开发数据库篇—SQLite常用的函数

iOS开发数据库篇—SQLite常用的函数 一.简单说明 1.打开数据库 int sqlite3_open( const char *filename,   // 数据库的文件路径 sqlite3 **ppDb          // 数据库实例 ); 2.执行任何SQL语句 int sqlite3_exec( sqlite3*,                                  // 一个打开的数据库实例 const char *sql,                    

IOS开发数据库篇—SQLite模糊查询

IOS开发数据库篇—SQLite模糊查询 一.示例 说明:本文简单示例了SQLite的模糊查询 1.新建一个继承自NSObject的模型 该类中的代码: 1 // 2 // YYPerson.h 3 // 03-模糊查询 4 // 5 // Created by apple on 14-7-27. 6 // Copyright (c) 2014年 wendingding. All rights reserved. 7 // 8 9 #import <Foundation/Foundation.h

C/C++笔试忍法帖03——数据库篇

1.存储过程是什么?有什么用?有什么优点? 存储过程(Stored Procedure)是一组为了完成特定功能的SQL 语句集,经编译后存储在数据库中,用户通过指定存储过程的名字并给出参数(如果该存储过程带有参数)来执行它. 存储过程用于实现频繁使用的查询.业务规则.被其他过程使用的公共例行程序. 存储过程在创建时即在服务器上进行编译,所以执行起来比单个 SQL 语句快. 2.一般数据库若出现日志满了,会出现什么情况,是否还能使用? 答:只能执行查询等读操作,不能执行更改,备份等写操作,原因是任