我正在按烧瓶开发小型CRM系统。现在,当我通过邮递员测试import_data.py时出现错误。真的不知道如何解决此问题。...我已经测试过将数据手动插入MySQL DB,并且可以正常工作。我不确定是哪一部分导致了问题,但我认为问题应该出在app.py或import_data.py,或者是我在Postman下测试的方式。这是我的项目的结构。
项目结构
这是app.py的编码
# -*- coding:utf-8 -*-
import pandas as pd
from flask import Flask, request
import logging; logging.basicConfig(level=logging.INFO)
import asyncio, os, json, time
from datetime import datetime
from util.template import ReponseTemplate
from aiohttp import web
from api import import_data, statistic, general_search
import sys
import traceback
from werkzeug.utils import secure_filename
# UPLOAD_FOLDER = '/path/to/the/uploads'
ALLOWED_EXTENSIONS = set(['xlsx', 'xls', 'csv'])
app = Flask(__name__)
# app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
app.config['MAX_CONTENT_LENGTH'] = 60 * 1024 * 1024
app.register_blueprint(import_data.mold, url_prefix='/api/import')
app.register_blueprint(general_search.mold, url_prefix='/api/show')
app.register_blueprint(statistic.mold, url_prefix='/api/check')
def allowed_file(filename):
return '.' in filename and \
filename.rsplit('.', 1)[1] in ALLOWED_EXTENSIONS
@app.route('/upload', methods=['POST'])
def upload_excel():
f = request.files['file']
if f and allowed_file(f.filename):
filename = secure_filename(f.filename)
f.save(secure_filename(filename))
# file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
df = pd.read_excel(f)
return ReponseTemplate().jsonify_ok_df_response(df)
@app.errorhandler(Exception)
def default_exception_handler(error):
exc_type, exc_value, exc_traceback = sys.exc_info()
trace = traceback.format_exception(exc_type, exc_value,
exc_traceback)
code = 401 if 'auth' in str(type(error)).lower() else 400
print('[Error]:{}'.format(trace))
return ReponseTemplate().jsonify_bad_response(str(error), code)
if __name__ == '__main__':
app.run(debug=True)
这里是template.py的编码
import math
import simplejson as json
from flask import jsonify
class ResponseTemplate():
response_template = {
"success": "Success",
"data": [],
"meta": {
"code": 200,
"message": "OK",
"errors": [],
"pages": {}
}
}
def jsonify_ok_row_response(self, rows, page_index=1, page_size=10, total=0):
self.response_template['meta']['errors'] = []
self.response_template['meta']['code'] = 200
if rows is None:
self.response_template['data'] = []
else:
json_result = [{key.lower(): value for (key, value) in row.items()} for row in rows]
self.response_template['data'] = json_result
pages = {"limit": 1, "page": 1, "total": 0, "count": 0}
pages['limit'] = page_size
pages['page'] = page_index
pages['count'] = int(math.ceil(float(total) / page_size))
pages['total'] = total if total > 0 else len(self.response_template['data'])
self.response_template['meta']['pages'] = pages
return jsonify(self.response_template)
def jsonify_ok_list_response(self, data, page_index=1, page_size=10, total=0):
self.response_template['meta']['errors'] = []
self.response_template['meta']['code'] = 200
if data is None:
self.response_template['data'] = []
else:
json_result = [{key.lower(): value for (key, value) in d.items()} for d in data]
self.response_template['data'] = json_result
pages = {"limit": 1, "page": 1, "total": 0, "count": 0}
pages['limit'] = page_size
pages['page'] = page_index
pages['count'] = int(math.ceil(float(total) / page_size))
pages['total'] = total if total > 0 else len(self.response_template['data'])
self.response_template['meta']['pages'] = pages
return jsonify(self.response_template)
def jsonify_ok_str_response(self, json_str, page_index=1, page_size=10, total=0):
self.response_template['meta']['errors'] = []
self.response_template['meta']['code'] = 200
if json_str is None or json_str == '':
self.response_template['data'] = []
else:
json_result = json.loads(json_str)
self.response_template['data'] = json_result
pages = {"limit": 1, "page": 1, "total": 0, "count": 0}
pages['limit'] = page_size
pages['page'] = page_index
pages['count'] = int(math.ceil(float(total) / page_size))
pages['total'] = total if total > 0 else len(self.response_template['data'])
self.response_template['meta']['pages'] = pages
return jsonify(self.response_template)
def jsonify_ok_obj_response(self, obj, page_index=1, page_size=10, total=0):
self.response_template['meta']['errors'] = []
self.response_template['meta']['code'] = 200
if obj is None:
self.response_template['data'] = []
else:
self.response_template['data'] = obj
pages = {"limit": 1, "page": 1, "total": 0, "count": 0}
pages['limit'] = page_size
pages['page'] = page_index
pages['count'] = int(math.ceil(float(total) / page_size))
pages['total'] = total if total > 0 else len(self.response_template['data'])
self.response_template['meta']['pages'] = pages
return jsonify(self.response_template)
def jsonify_ok_df_response(self, df, page_index=1, page_size=10, total=0, orient='records'):
self.response_template['meta']['errors'] = []
self.response_template['meta']['code'] = 200
if df is None:
self.response_template['data'] = []
else:
json_str = df.to_json(orient=orient)
json_result = json.loads(json_str)
self.response_template['data'] = json_result
pages = {"limit": 1, "page": 1, "total": 0, "count": 0}
pages['limit'] = page_size
pages['page'] = page_index
pages['count'] = int(math.ceil(float(total) / page_size))
pages['total'] = total if total > 0 else len(self.response_template['data'])
self.response_template['meta']['pages'] = pages
return jsonify(self.response_template)
def jsonify_bad_response(self, errors, code):
self.response_template['meta']['errors'] = errors
self.response_template['meta']['code'] = code
self.response_template['data'] = []
self.response_template['meta']['pages'] = {}
return jsonify(self.response_template)
这是import_data.py
# -*- coding:utf-8 -*-
import json
from flask import Blueprint, request
from util.template import ResponseTemplate
import logging
from model.dbmodel import Customers, Transaction
from sqlalchemy.orm import mapper, sessionmaker
from sqlalchemy import create_engine
import config
import pandas as pd
from sqlalchemy.ext.declarative import declarative_base
mold = Blueprint('import', __name__)
conn = config.conn_str
Base = declarative_base()
@mold.route('/customer', methods=['POST'])
def import_customer():
engine = create_engine(conn)
# df = pd.read_excel(request.data)
cum = json.loads(request.data)
if cum is None:
logging.info("Not able to get the data from request.")
# Customers.name = cum.get('name', '')
# Customers.address = cum.get('address', '')
# Customers.phone = cum.get('phone', '')
# Customers.source_from = cum.get('source_from', '')
name = cum.get('name', '')
address = cum.get('address', '')
phone = cum.get('phone', '')
source_from = cum.get('source_from', '')
Base.metadata.create_all(engine)
Session_class = sessionmaker(bind=engine)
session = Session_class()
# generate the object for the data we would like to insert
customer_obj = Customers(name=name, address=address,
phone=phone, source_from=source_from)
# nothing yet, print to check
print(customer_obj.id, customer_obj.name,
customer_obj.phone, customer_obj.address,
customer_obj.source_from)
session.add(customer_obj) # put the data obj into session, will insert together
# check again. but still nothing yet....
print(customer_obj.id, customer_obj.name,
customer_obj.phone, customer_obj.address,
customer_obj.source_from)
session.commit() # insert the data into database
return ResponseTemplate.jsonify_ok_obj_response(customer_obj)
@mold.route('/transactions/<file_name>', methods=['POST'])
def import_transactions(file_name):
engine = create_engine(conn)
#df = pd.read_excel(request.data)
#tran = json.loads(request.data)
tran = pd.read_excel(file_name)
if tran is None:
logging.info("Not able to get the data from file.")
name = tran.get('name', '')
# print(name)
date = tran.get('date', '')
# print(date)
product = tran.get('product', '')
# print(product)
quantity = tran.get('quantity', '')
amount = tran.get('amount', '')
Base.metadata.create_all(engine)
Session_class = sessionmaker(bind=engine)
session = Session_class()
# generate the object for the data we would like to insert
transaction_obj = Transaction(name=name, date=date, product=product,
quantity=quantity, amount=amount)
# print to check, there should be nothing yet
print(transaction_obj.name, transaction_obj.product, transaction_obj.date,
transaction_obj.quantity, transaction_obj.amount)
session.add(transaction_obj) # put the data into obj
# check again, there should be nothing still
print(transaction_obj.name, transaction_obj.product, transaction_obj.date,
transaction_obj.quantity, transaction_obj.amount)
session.commit() # insert
return ResponseTemplate.jsonify_ok_obj_response(transaction_obj)
此处为数据库中的两个表编码:dbmodel.py
# -*- coding:utf-8 -*-
from sqlalchemy import Table, MetaData, Column, Integer, String, DATE, DECIMAL, ForeignKey, DateTime
from sqlalchemy.orm import mapper
from sqlalchemy.ext.declarative import declarative_base
#metadata = MetaData()
Base = declarative_base()
# customers = Table('customers', metadata,
# Column('id', Integer, primary_key=True, autoincrement=True),
# Column('name', String(20)),
# Column('phone', String(20)),
# Column('address', String(45)),
# Column('source_from', String(45))
# )
class Customers(Base):
# def __init__(self, id, name, phone, address, source_from):
# self.id = id
# self.name = name
# self.phone = phone
# self.address = address
# self.source_from = source_from
#
# def __repr__(self):
# return "<Customer(name='%s', phone='%s', address='%s', " \
# "source_from='%s')" % (self.name, self.phone, self.address,
# self.source_from)
__tablename__ = 'customers'
id = Column(Integer, primary_key=True, autoincrement=True, nullable=False)
name = Column(String(20))
phone = Column(String(20))
address = Column(String(45))
source_from = Column(String(45))
# mapper(Customers, customers)
# the table metadata is created separately with the Table construct,
# then associated with the User class via the mapper() function
# transaction = Table('transaction', metadata,
# Column('id', Integer, primary_key=True, autoincrement=True),
# Column('name', String(20)),
# Column('date', DateTime),
# Column('product', String(20)),
# Column('quantity', Integer),
# Column('amount', DECIMAL(2))
# )
class Transaction(Base):
# def __init__(self, id, name, date, product, quantity, amount):
# self.id = id
# self.name = name
# self.date = date
# self.product = product
# self.quantity = quantity
# self.amount = amount
#
# def __repr__(self):
# return "<Transaction(name='%s', date='%s', product='%s'," \
# "quantity='%s', amount='%s')>" % (self.name, self.date,
# self.product, self.quantity,
# self.amount)
__tablename__ = 'transaction'
id = Column(Integer, primary_key=True, autoincrement=True, nullable=False)
name = Column(String(20))
date = Column(DATE)
product = Column(String(20))
quantity = Column(Integer)
amount = Column(Integer)
# mapper(Transaction, transaction)
下面的链接是我测试api后邮递员结果的屏幕截图:
邮递员测试结果
以下是我用邮递员测试api后来自pycharm的错误消息:
[Error]:['Traceback (most recent call last):\n', ' File
"/Applications/anaconda3/envs/Fruit/lib/python3.6/site-packages/flask/app.py", line 1813, in full_dispatch_request\n rv = self.dispatch_request()\n',
' File "/Applications/anaconda3/envs/Fruit/lib/python3.6/site-packages/flask/app.py", line 1799, in dispatch_request\n
return self.view_functionsrule.endpoint \ n','文件“ /Users/chenneyhuang/PycharmProjects/Fruit/api/import_data.py”,第91行,位于import_transactions \ n session.commit()#insert \ n', '文件“ /Applications/anaconda3/envs/Fruit/lib/python3.6/site-packages/sqlalchemy/orm/session.py”,第943行,位于commit \ n self.transaction.commit()\ n','文件“ /Applications/anaconda3/envs/Fruit/lib/python3.6/site-packages/sqlalchemy/orm/session.py”,第467行,位于commit \ n self._prepare_impl()\ n','File“ / Applications / anaconda3 / envs / Fruit / lib / python3.6 / site-packages / sqlalchemy / orm / session.py“,第447行,位于_prepare_impl \ n self.session.flush()\ n','File'/ Applications /anaconda3/envs/Fruit/lib/python3.6/site-packages/sqlalchemy/orm/session.py“,第2254行,在flush \ n self._flush(objects)\ n','File” / Applications / anaconda3中/envs/Fruit/lib/python3.6/site-packages/sqlalchemy/orm/session.py“,第2380行,在_flush \ n transaction.rollback(_capture_exception = True)\ n','File” / Applications / an aconda3 / envs / Fruit / lib / python3.6 / site-packages / sqlalchemy / util / langhelpers.py“,第66行,位于退出 \ n compat.reraise(exc_type,exc_value,exc_tb)\ n','File“ /Applications/anaconda3/envs/Fruit/lib/python3.6/site-packages/sqlalchemy/util/compat.py”,第249行,以提高\ n提高价值\ n','File' /Applications/anaconda3/envs/Fruit/lib/python3.6/site-packages/sqlalchemy/orm/session.py“,第2344行,位于_flush \ n flush_context.execute()\ n','File” / Applications / anaconda3 / envs / Fruit / lib / python3.6 / site-packages / sqlalchemy / orm / unitofwork.py“,第391行,位于execute \ n rec.execute(self)\ n','File” / Applications / anaconda3 / envs / Fruit / lib / python3.6 / site-packages / sqlalchemy / orm / unitofwork.py“,行556,在execute \ n uow \ n','File” / Applications / anaconda3 / envs / Fruit / lib / python3中.6 / site-packages / sqlalchemy / orm / persistence.py“,第181行,在save_obj \ n映射器中,表中,插入)\ n','File” /Applications/anaconda3/envs/Fruit/lib/python3.6 / site-packages / sqlalchemy / orm / pers istence.py”,第866行,位于_emit_insert_statements \ n execute(statement,params)\ n','File“ /Applications/anaconda3/envs/Fruit/lib/python3.6/site-packages/sqlalchemy/engine/base中。 py”,第948行,在execute \ n中返回meth(self,multiparams,params)\ n','File“ /Applications/anaconda3/envs/Fruit/lib/python3.6/site-packages/sqlalchemy/sql/elements .py“,第269行,位于_execute_on_connection \ n返回连接中。_execute_clauseelement(自身,多参数,参数)\ n','File” /Applications/anaconda3/envs/Fruit/lib/python3.6/site-packages/sqlalchemy/引擎/base.py”中的第1060行,位于_execute_clauseelement \ n中,\ n configure_sql,stilled_params \ n',“文件” /Applications/anaconda3/envs/Fruit/lib/python3.6/site-packages/sqlalchemy/engine/base.py “,第1200行,在_execute_context \ n上下文中)\ n','文件” /Applications/anaconda3/envs/Fruit/lib/python3.6/site-packages/sqlalchemy/engine/base.py“,第1416行,在_handle_dbapi_exception \ n util.reraise(* exc_info)\ n','File“ / Applications / anaconda3 / e nvs / Fruit / lib / python3.6 / site-packages / sqlalchemy / util / compat.py”,第249行,以提高\ n提高价值\ n',“文件” / Applications / anaconda3 / envs / Fruit / lib / python3.6 / site-packages / sqlalchemy / engine / base.py“,第1193行,在_execute_context \ n上下文中)\ n','File” /Applications/anaconda3/envs/Fruit/lib/python3.6/site-包/sqlalchemy/engine/default.py”,行509,位于do_execute \ n cursor.execute(语句,参数)\ n','文件“ /Applications/anaconda3/envs/Fruit/lib/python3.6/site-包/pymysql/cursors.py”,第168行,位于execute \ n query = self.mogrify(query,args)\ n','File“ /Applications/anaconda3/envs/Fruit/lib/python3.6/site-软件包/pymysql/cursors.py”,第147行,在mogrify \ n query = query%self._escape_args(args,conn)\ n','File“ /Applications/anaconda3/envs/Fruit/lib/python3.6/ _escape_args \ n中的site-packages / pymysql / cursors.py“,第127行,返回args.items()中(key,val)的dict((key,conn.literal(val)))\ n','File “ / Applications / anaconda3 / envs / Fruit / li b / python3.6 / site-packages / pymysql / cursors.py“,第127行,\ n在args.items()中返回dict((key,conn.literal(val))for(key,val)\ n',“文件” /Applications/anaconda3/envs/Fruit/lib/python3.6/site-packages/pymysql/connections.py”,第469行,字面意思\ n返回self.escape(obj,self.encoders) \ n','文件“ /Applications/anaconda3/envs/Fruit/lib/python3.6/site-packages/pymysql/connections.py”,第462行,位于转义符\ n返回converters.escape_item(obj,self.charset ,mapping = mapping)\ n','文件“ /Applications/anaconda3/envs/Fruit/lib/python3.6/site-packages/pymysql/converters.py”,第27行,位于escape_item \ n val = encoder(val ,映射)\ n','File“ /Applications/anaconda3/envs/Fruit/lib/python3.6/site-packages/pymysql/converters.py”,第118行,在escape_unicode \ n中返回u“ \'%s \'“%_escape_unicode(value)\ n','File” /Applications/anaconda3/envs/Fruit/lib/python3.6/site-packages/pymysql/converters.py“,第73行,在_escape_unicode \ n中返回值.translate(_escape_table)\ n',在 getattr \ n返回对象中的文件“ /Applications/anaconda3/envs/Fruit/lib/python3.6/site-packages/pandas/core/generic.py”第4376行。 > getattribute ((自身,名称)\ n”,“ AttributeError:'Series'对象没有属性'translate'\ n”]
我正在使用python3.6。 这是软件包的详细信息:
aiohttp==3.3.2
aiomysql==0.0.19
asn1crypto==0.24.0
async-timeout==3.0.0
attrs==18.1.0
cffi==1.11.5
chardet==3.0.4
click==6.7
cryptography==2.2.2
Flask==1.0.2
idna==2.7
idna-ssl==1.1.0
itsdangerous==0.24
Jinja2==2.10
MarkupSafe==1.0
multidict==4.3.1
numpy==1.15.0
pandas==0.23.4
pycparser==2.18
PyMySQL==0.9.2
python-dateutil==2.7.3
pytz==2018.5
simplejson==3.16.0
six==1.11.0
SQLAlchemy==1.2.10
Werkzeug==0.14.1
xlrd==1.1.0
yarl==1.2.6
答案 0 :(得分:0)
之所以发生这种情况,是因为您将一个对象从pandas
传递到了一个期望使用纯字符串的操作(如堆栈跟踪所示,它恰好是一个Series
对象)。
看看这个顺序:
tran = pd.read_excel(file_name)
name = tran.get('name', '')
tran
这里不是普通的Python dict
或list
,对其应用索引(使用tran[x]
或.get()
等)会返回复杂的数据结构,而不是字符串-即使原始输入数据(在excel文件中)是字符串。
如果您的.get('key')
操作从类型为str
的数据框中选择一个值,则需要将其显式转换为Python字符串,而不能仅将其提供给需要的数据库函数字符串,并神奇地期望它变成字符串:
name = str ( tran.get('name', '' ) )
不过,我怀疑它实际上会为您提供一列值-您需要对代码进行一些更改才能处理该问题。
(顺便说一句,如果您只需要从XLS或CSV到Python数据的简单转换,pandas
似乎是一个沉重的怪物。对于CSV,有一个本地Python库;尽管位于顶部我的头,我没有现在可以推荐的XLS转换器。