flask或flask-restful的接口开发,返回的json数据能显示中文的方法

用flask或flask-restful开发接口时,返回给前端的json数据中若有中文,在postman的raw里或浏览器直接访问,中文会显示成unicode编码之后的形式,下面是使之显示成中文的方法。

情况一

若没用Flask-RESTful,只用flask,针对视图函数里下面三种返回的方法,只要创建app后加一句配置,app.config['JSON_AS_ASCII']=False,则postman的raw数据或浏览器直接访问,都显示中文。参考链接1,参考链接2

  • return {'msg':'状态'}
  • return jsonify(msg='状态')
  • 先定义字典dic={'msg':'状态'},再return json.dumps(dic)

如果不加配置代码,可以在返回时加参数,如return json.dumps(dic,ensure_ascii=False),也显示中文。返回值还含有中文时,默认为ASCII编码,中文为Unicode编码,参考链接3

情况二

若用Flask-RESTful,类视图的post()函数(只是举例,get()或其他也行)中有

data={
            'message':'新闻发表成功',
            'status':200,
            'news':marshal(news,news_detail_fields)
        }

marshal()内的news是News类的对象,一个news对象就是一条新闻,数据库中有多条新闻,模型代码

class BaseModel(db.Model):
    __abstract__=True # 作为抽象类,不能单独作为模型出现,只能作父类
    id=db.Column(db.Integer,primary_key=True,autoincrement=True)
    timestamp=db.Column(db.DateTime,default=datetime.utcnow)


class NewsType(BaseModel):
    __tablename__='news_type' # 不写这句和父类中的__abstract__,生成的表名是base_model
    type=db.Column(db.String(50),nullable=False)


class News(BaseModel):
    __tablename__='news'
    title=db.Column(db.String(100),nullable=False)
    content=db.Column(db.Text,nullable=False)
    type_id=db.Column(db.Integer,db.ForeignKey('news_type.id'))
    user_id=db.Column(db.Integer, db.ForeignKey('user.id'))
    is_deleted=db.Column(db.Boolean,default=False)
    comments=db.relationship('NewsComment',backref='news')


class NewsComment(BaseModel):
    __tablename__='news_comment'
    content=db.Column(db.String(256),nullable=False)
    star_times=db.Column(db.Integer,default=0) # 点赞量
    news_id=db.Column(db.Integer,db.ForeignKey('news.id')) # 被评论的新闻的id
    user_id=db.Column(db.Integer,db.ForeignKey('user.id')) # 发表评论的人的id
    replies=db.relationship('Reply',backref='comment')


class User(BaseModel):
    __tablename__='user'
    username=db.Column(db.String(50),unique=True,nullable=True)
    password=db.Column(db.String(128)) # 短信登录时,若当前手机号未注册,则自动注册。这时由于是短信登录,所以没有密码,所以创建用户时可以没有密码
    phone=db.Column(db.String(11),unique=True,nullable=True)
    portrait_file_name=db.Column(db.String(64))
    is_deleted=db.Column(db.Boolean,default=False)
    news=db.relationship('News',backref='author') # 根据新闻查作者
    comments=db.relationship('NewsComment',backref='user')
    replies=db.relationship('Reply',backref='user')


class Reply(BaseModel): # 对评论的回复
    __tablename__='reply'
    content=db.Column(db.String(256),nullable=False)
    star_times=db.Column(db.Integer,default=0) # 点赞量
    comment_id=db.Column(db.Integer,db.ForeignKey('news_comment.id')) # 被回复的评论的id
    user_id=db.Column(db.Integer,db.ForeignKey('user.id')) # 发表回复的人的id

向数据库手动添加一些新闻再测试。

然后post()函数返回了data,有多种返回方式,我将对应的结果放在后面的表格里。如果复制下面的代码去测试,请自行导入相关库、创建api及其他对象。postman里选POST,地址http://127.0.0.1:5000/news,Body的form-data里,KEY有type_id、title、content,再填上对应的VALUE,然后提交。如果懒得POST,在数据库里有数据的前提下,自己写个GET的接口也可以测试,如获取所有的新闻类型。

add_news_parser=reqparse.RequestParser()
add_news_parser.add_argument('title',type=str,help='请输入新闻标题',required=True,location='form') # 接收要发布的新闻的标题
add_news_parser.add_argument('content',type=str,help='请输入新闻内容',required=True,location='form') # 接收要发布的新闻的内容
add_news_parser.add_argument('type_id',type=int,help='请选择新闻类型',required=True,location='form') # 接收要发布的新闻的类型的id

reply_fields={ # 对评论的回复的格式
    'user':AuthorName(attribute='user'),
    'content':fields.String,
    'datetime':fields.DateTime(attribute='timestamp'),
    'star_times':fields.Integer
}
comment_fields={ # 评论的格式
    'user':AuthorName(attribute='user'),
    'content':fields.String,
    'datetime':fields.DateTime(attribute='timestamp'),
    'star_times':fields.Integer,
    'replies':fields.List(fields.Nested(reply_fields)) # 对评论的回复
}
news_detail_fields={ # 新闻详情的格式,即点击某条新闻后展示的完整内容
    'id':fields.Integer,
    'title':fields.String,
    'content':fields.String, # 数据库中是Text类型,fields中无Text类型,可用String代替
    'datetime':fields.DateTime(attribute='timestamp'),
    'author':AuthorName(attribute='author'),
    'comments':fields.List(fields.Nested(comment_fields)) # comments里是NewsComment对象,不能直接放在fields.List()里,fields.Nested()支持嵌套形式的json,里面传入字典,会把NewsComment对象转成前面传入的字典的格式,然后放在List里。from https://flask-restful.readthedocs.io/en/latest/fields.html#list-field和https://flask-restful.readthedocs.io/en/latest/fields.html#advanced-nested-field
}


class NewsResource(Resource): # 新闻的类视图
    def post(self): # 发表新闻
        args=add_news_parser.parse_args()
        title=args.get('title')
        content=args.get('content')
        type_id=args.get('type_id')
        news=News(title=title,content=content,type_id=type_id,user_id=g.user.id)
        db.session.add(news)
        db.session.commit()
        data={
            'message':'新闻发表成功',
            'status':200,
            'news':marshal(news,news_detail_fields)
        }
        return data
        # return jsonify(message='新闻发表成功',status=200,news=marshal(news,news_detail_fields))
        # return json.dumps(data)
        # return json.dumps(data,ensure_ascii=False)

api.add_resource(NewsResource,'/news')

将app.config['JSON_AS_ASCII']=False称为配置代码1,将app.config.update(RESTFUL_JSON=dict(ensure_ascii=False))称为配置代码2。

json是通过import json导入的,不是from flask import json,因从flask导入的json在json.dumps()里输参数ensure_ascii=False时没自动补全。

上面代码的各种返回值
 创建app后不加配置代码创建app后加配置代码1创建app后加配置代码2
return dataunicodeunicode中文
return jsonify(message='新闻发表成功',status=200,news=marshal(news,news_detail_fields))unicode中文unicode
return json.dumps(data)unicode且有很多\unicode且有很多\unicode且有很多\
return json.dumps(data,ensure_ascii=False)unicode且有很多\unicode且有很多\中文且有很多\

如果你的返回值是简单的纯json,而不像我那样里面有对象,返回值的数据编码已测试与上表一致。因我的对象用marshal()或@marshal_with()序列化过了,返回值已经是真正的json数据。flask-restful接口返回的数据只能是纯json形式,里面不能有对象,否则无法返回。

json.dumps()和jsonify()都是将字典转为字符串,但响应头不同,json.dumps()返回的是Content-Type:text/html,jsonify()返回的是Content-Type:application/json。参考链接4。可能因为json.dumps()不是真正的json形式,或是其他原因,导致代码中json.dumps()只返回unicode编码的数据,而jsonify()在加了那句配置代码的前提下能返回正常显示中文的数据。

接口返回的中文无法显示的原因

flask是支持中文的,官方的方法是添加app.config['JSON_AS_ASCII']=False。所以可以解决情况一。官方文档1,官方文档2。

但flask-restful使用的json是Python标准库中的模块(官方文档3),导致flask官方的方法失效,而标准库的json要想显示中文,就必须json.dumps(data,ensure_ascii=False)。flask-restful的源码中,是想读取你的用户配置(如图箭头),从而达到控制 json.dumps()。源码内没有手动配置的话,默认就是ensure_ascii为True,因这里它的dumped = dumps(data, **settings) + "\n"就是反向映射(图片未截全,自行去源码里看)。

所以若用flask-restful,除了添加那句配置代码2,也可以直接修改源码(修改后不用再在创建app后添加那句配置代码,图中我已修改源码)

  • 在pycharm里按ctrl点flask_restful进入一个__init__.py文件
  • 再点from flask_restful.representations.json import output_json中的json或output_json
  • 在settings = current_app.config.get('RESTFUL_JSON', {})的下一行添加settings['ensure_ascii'] = False

app.config.update(RESTFUL_JSON=dict(ensure_ascii=False))是通过app.config指定flask_restful取消ensure_ascii。

本文未用到的参考链接5,参考链接6,参考链接7。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Flask-RESTful 中,可以使用 request_parser 来预处理 POST 请求中的 JSON 数据。使用 request_parser 可以在处理 JSON 数据之前对数据进行验证和预处理,以确保数据的有效性。以下是一个使用 request_parser 预处理 JSON 数据的示例: ``` from flask import Flask, request from flask_restful import Api, Resource, reqparse app = Flask(__name__) api = Api(app) parser = reqparse.RequestParser() parser.add_argument('name', type=str, required=True, help='Name is required') parser.add_argument('age', type=int, required=True, help='Age is required') class User(Resource): def post(self): args = parser.parse_args() name = args['name'] age = args['age'] # perform validation and pre-processing on the data here # ... # return the response return {'name': name, 'age': age} api.add_resource(User, '/user') if __name__ == '__main__': app.run(debug=True) ``` 在上面的示例中,我们首先创建了一个 RequestParser 对象,然后使用 add_argument 方法添加需要解析的参数。接下来,在 User 类的 post 方法中,我们使用 parser.parse_args() 方法解析 POST 请求中的 JSON 数据,并从解析结果中获取 name 和 age 参数。我们可以在获取参数之后对数据进行验证和预处理,完成后再返回响应。 需要注意的是,Flask-RESTful 会自动将返回值序列化为 JSON 格式,并设置 Content-Type 头为 application/json。因此,在返回响应时,只需要返回一个 Python 字典即可,无需手动进行 JSON 序列化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值