flask接口实现(返回csv、json)

Flask官方文档:https://dormousehole.readthedocs.io/en/latest/index.html

本flask接口实现功能

1)入参无‘json’时,返回csv文件

2)入参json有任意值(如:json=1)时,在前端返回json

3)各入参均可接收多个(以逗号分隔,如 http://0.0.0.0:8888/myapi?studentId=101,102&classId=2,5   将查询classId为2或5、且studentId为101或102的学生信息)

4)入参中只需保证一个不为空

 

#grade_api.py

# -- coding:UTF-8 --
import json
import time
import os
from flask import Flask, request, send_from_directory, make_response, jsonify
import logging
import configparser
from datetime import timedelta, datetime

import grade_record

app = Flask(__name__) #创建flask对象
app.config['SEND_FILE_MAX_AGE_DEFAULT'] = timedelta(seconds=2)
# flask对象的config属性;SEND_FILE_MAX_AGE_DEFAULT:默认缓存控制的最大期限,以秒计.
# 更多属性 http://docs.jinkan.org/docs/flask/config.html
app.config['JSON_AS_ASCII'] = False


TEMPLATES_AUTO_RELOAD = True

# 使用 route() 装饰器来告诉 Flask 触发函数的 URL 。
@app.route('/myapi', methods=['get', 'post']) 
def find_grade():
    student_id = request.values.get('studentId') # 获取请求对象
    student_id = get_list(student_id) #获取studentId列表

    class_id = request.values.get('classId')
    class_id = get_list(class_id) 
    json = request.values.get('json')

    if student_id or class_id :
        #只要一个入参不为空
        grade_record.get_record(student_id, class_id)  # 从sql库查询记录(且将记录转为csv)

        directory = os.getcwd()
        #若json参数不为空,则返回json,否则返回csv文件
        if json:
            response = make_response(jsonify(grade_record.get_df()))
        else:
            response = make_response(send_from_directory(directory, grade_record.get_file_name(), as_attachment=True))

        grade_record.remove_oudate_files(2)  # 删除当前目录下2min前的csv文件
        return response
    else:
        resu = {'code': 10001, 'message': '参数不能全为空!'}
        return json.dumps(resu, ensure_ascii=False)


def get_list(field_name):
    if field_name:
        return process_list(field_name)


def process_list(field_name):
#处理接收到的参数,转为list
    if field_name:
        field_list = list(field_name.split(','))
        return field_list
    else:
        print(field_name + 'is none')

if __name__ == '__main__':
    app.run(debug=config['api']['debug'], port=config['api']['port'], host=config['api']['host'])
#grade_record.py

# -*- coding:utf-8 -*-
import time
import pymysql
import configparser
import os
import numpy as np
import pandas as pd
import pressure
from sshtunnel import SSHTunnelForwarder
import paramiko

config = configparser.RawConfigParser()
config.read('config.ini', encoding='UTF-8')


def sql_conn():
    global conn_sql
    # 为"True"时,连接sql测试服
    if config['ssh']['ssh_connect'] == 'True':
        global server
        server = SSHTunnelForwarder(
            (config['ssh']['server_host'], 22),
            ssh_username=config['ssh']['ssh_username'],
            ssh_pkey='/Users/.ssh/id_rsa', #私钥地址
            remote_bind_address=(config['ssh']['remote_bind_address'], 3306)
        )
        server.start()
        conn_sql = pymysql.connect(host=config['sql_test']['host'],
                                   port=server.local_bind_port,
                                   user=config['sql_test']['user'],
                                   password=config['sql_test']['password'],
                                   db=config['sql_test']['db'],
                                   charset='utf8')

    global cur
    cur = conn_sql.cursor()


def get_sql_connection():
    return conn_sql


def get_sql_cursor():
    return cur


def sql_select(student_id, class_id):
    # sql查询语句
    sql_base = " SELECT class_id,student_id,grade FROM table_grade WHERE "
    global params
    params = [student_id, class_id]

    # 遍历接口入参列表params,不为空的项拼接其对应的sql语句
    count = 0
    for i in range(0, len(columns)):
        if params[i]:
            if count == 0:
                sql_base = sql_base + sql_joint(columns[i])
            else:
                sql_base = sql_base + ' AND ' + sql_joint(columns[i])
            count = count + 1
        else:
            continue
    return sql_base


def get_field_bunch(field_list_name):
    # 列表转化为()形式的字符串,便于sql查询
    field_bunch = '(%s)' % ','.join(map(str, field_list_name))
    return field_bunch


def sql_joint(field_name):
    if field_name == 'student_id':
        return "  student_id in " + get_field_bunch(params[0])
    elif field_name == 'class_id':
        return "  class_id in " + get_field_bunch(params[1])


def get_record(student_id, class_id):
    sql_conn()
    cur.execute(sql_select(student_id, class_id))
    result = cur.fetchall()

    df = pd.DataFrame(list(result),
                      columns=['class_id', 'student_id', 'grade'])

    cur_time = time.strftime('%Y%m%d_%H_%M_%S', time.localtime(time.time()))
    global file_name
    file_name = cur_time + '.csv'
    df_csv = df.to_csv(file_name, encoding='utf_8_sig', index=False)  # 取当前时间命名csv文件
    # 编码utf_8_sig能解决csv在windows中打开乱码的问题

    global df_dict
    df_dict = df.T.to_dict()

    conn_sql.commit()
    conn_sql.close()

    return df_csv


def get_df():
    return df_dict


def get_file_name():
    return file_name


def remove_oudate_files(minutes):
    # 删除当前目录下历史csv文件
    ts_before = time.time()
    path = os.getcwd()
    for file in os.listdir(path):
        filename = path + os.sep + file
        if filename.endswith('.csv'):
            if os.path.getatime(filename) < ts_before:
                try:
                    os.remove(filename)
                    print('%s remove success' % filename)
                except Exception as error:
                    print(error)
                    print('%s remove failed' % filename)

bug解决

bug 原因 解决  
结果中有中文字符时,flask返回的json里的中文为unicode编码(如\u5b66\u751f ... ) 默认情况下 Flask 使用 ascii 编码来序列化对象。 app.config['JSON_AS_ASCII'] = False
# JSON_AS_ASCII属性:默认情况下 Flask 使用 ascii 编码来序列化对象。如果这个值被设置为 False , Flask不会将其编码为 ASCII,并且按原样输出,返回它的 unicode 字符串。
 
 
若入参和上一次输入的相同,返回的csv文件仍是缓存中的上一个文件(文件名以生成时间命名的话,此时返回新文件名仍是上一次的时间)  

app.config['SEND_FILE_MAX_AGE_DEFAULT'] = timedelta(seconds=2) 

# 设置默认缓存控制的最大期限,以秒计。

 
dataframe转 json,并在response中 flask的jsonify方法不能直接转dataframe; 但可以直接转字典 先将dataframe转为dict,再用 jsonify(dict)

jsonify()和json.dumps()的区别 

 

jsonify不仅会将内容转换为json,而且也会修改Content-Type为application/json。

 

用json.dumps时,HTTP返回的Content-Type仍然是text/html

还需要手动设置 content_type:

return Response(json.dumps(t), mimetype='application/json')


 

       

       

你可能感兴趣的:(项目,Python)