前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Flask 学习-37.Flask-RESTful 序列化输出fields 字段设置

Flask 学习-37.Flask-RESTful 序列化输出fields 字段设置

作者头像
上海-悠悠
发布2022-09-06 14:17:51
7870
发布2022-09-06 14:17:51
举报

前言

前面一篇使用Flask-RESTful 已经实现查询对象的序列化输出成json,这篇继续讲下一些特殊字段的处理

模型

user 表结构设计

代码语言:javascript
复制
from . import db
from passlib.hash import sha256_crypt
from datetime import datetime

class Users(db.Model):
    __tablename__ = 'user'  # 数据库表名
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    username = db.Column(db.String(50), unique=True, nullable=False)
    password = db.Column(db.String(128), nullable=False)
    is_active = db.Column(db.Boolean, default=1)
    email = db.Column(db.String(64), nullable=True)
    create_time = db.Column(db.DateTime, default=datetime.now)
    update_time = db.Column(db.DateTime, onupdate=datetime.now, default=datetime.now)

    def hash_password(self, password):
        """密码加密"""
        self.password = sha256_crypt.encrypt(password)

    def verify_password(self, password):
        """校验密码"""
        return sha256_crypt.verify(password, self.password)

    def __repr__(self):
        return f"<Users(id='{self.id}', username='{self.username}'...)>"

日期字段

create_time 和 update_time 是DateTime 时间类型

代码语言:javascript
复制
from flask_restful import Resource, fields, marshal_with, marshal

user_fields = {
    'id': fields.Integer,
    'username': fields.String,
    'is_active': fields.Boolean,
    'create_time': fields.DateTime,
    'update_time': fields.DateTime,
}

class UserInfo(Resource):

    def get(self):
        user = Users.query.get(1)
        print(f'查询到的数据:{user}')
        print(user.update_time)
        return {
            "code": 0,
            "msg": "success",
            "data": marshal(user, user_fields)
        }

序列化后看到的时间格式如下

代码语言:javascript
复制
{
    "code": 0,
    "msg": "success",
    "data": {
        "id": 1,
        "username": "test",
        "is_active": true,
        "create_time": "Fri, 02 Sep 2022 10:24:48 -0000",
        "update_time": "Fri, 02 Sep 2022 10:24:51 -0000"
    }
}

在官方文档中可以看到,DateTime类型可以支持2种时间格式 RFC 822ISO 8601

代码语言:javascript
复制
user_fields = {
    'id': fields.Integer,
    'username': fields.String,
    'is_active': fields.Boolean,
    'create_time': fields.DateTime(dt_format='iso8601'),
    'update_time': fields.DateTime(dt_format='rfc822')
}

接下来看下这2种日期格式的显示

代码语言:javascript
复制
HTTP/1.1 200 OK
Server: Werkzeug/2.2.2 Python/3.8.5
Date: Fri, 02 Sep 2022 02:39:01 GMT
Content-Type: application/json
Content-Length: 236
Connection: close

{
    "code": 0,
    "msg": "success",
    "data": {
        "id": 1,
        "username": "test",
        "is_active": true,
        "create_time": "2022-09-02T10:24:48",
        "update_time": "Fri, 02 Sep 2022 10:24:51 -0000"
    }
}

很显然iso8601 格式的日期有个T,不是我们需要的。但是官方给的文档说只支持这2种格式,如果想输出自己想要的格式,就需要自定义字段了。

自定义字段和多个值

先看下官方文档给的示例: 有时您有自己的自定义格式需求。您可以子类化 fields.Raw该类并实现该format功能。这在属性存储多条信息时特别有用。 例如,一个位域,其各个位代表不同的值。您可以使用字段将单个属性多路复用到多个输出值。 此示例假定flags属性中的第 1 位表示“正常”或“紧急”项目,第 2 位表示“已读”或“未读”。 这些项目可能很容易存储在位域中,但对于人类可读的输出,最好将它们转换为单独的字符串字段。

自定义格式是使用 fields.Raw,继承 fields.Raw 然后实现 format 函数,官方的例子:

代码语言:javascript
复制
class UrgentItem(fields.Raw):
    def format(self, value):
        return "Urgent" if value & 0x01 else "Normal"

class UnreadItem(fields.Raw):
    def format(self, value):
        return "Unread" if value & 0x02 else "Read"

fields = {
    'name': fields.String,
    'priority': UrgentItem(attribute='flags'),
    'status': UnreadItem(attribute='flags'),
}

接下来自定义 CustomDate, 需重写format方法

代码语言:javascript
复制
from flask_restful import fields

class CustomDate(fields.DateTime):
    '''
    自定义CustomDate,原有的fileds.DateTime序列化后
    只支持 rfc822,ios8601 格式,新增 strftime 格式
    strftime格式下支持 format 参数,默认为 '%Y-%m-%d %H:%M:%S'
    '''

    def __init__(self, dt_format='rfc822', format=None, **kwargs):
        super().__init__(**kwargs)
        self.dt_format = dt_format

    def format(self, value):
        if self.dt_format in ('rfc822', 'iso8601'):
            return super().format(value)
        elif self.dt_format == 'strftime':
            if isinstance(value, str):
                return value
            return value.strftime('%Y-%m-%d %H:%M:%S')

        else:
            raise Exception('Unsupported date format %s' % self.dt_format)

使用示例

代码语言:javascript
复制
user_fields = {
    'id': fields.Integer,
    'username': fields.String,
    'is_active': fields.Boolean,
    'create_time': CustomDate(dt_format='iso8601'),
    'update_time': CustomDate(dt_format='strftime')
}

重命名属性

通常,您面向公众的字段名称与您的内部字段名称不同。要配置此映射,请使用attribute关键字参数。

代码语言:javascript
复制
user_fields = {
    'id': fields.Integer,
    'name': fields.String(attribute='username'),
    'is_active': fields.Boolean,
    'create_time': CustomDate(dt_format='iso8601'),
    'update_time': CustomDate(dt_format='strftime')
}

输出的 name 字段对应数据库的 username

代码语言:javascript
复制
{
    "code": 0,
    "msg": "success",
    "data": {
        "id": 1,
        "name": "test",
        "is_active": true,
        "create_time": "2022-09-02T10:24:48",
        "update_time": "2022-09-02 10:24:51"
    }
}

默认值

如果由于某种原因您的数据对象在字段列表中没有属性,您可以指定要返回的默认值而不是None.

代码语言:javascript
复制
user_fields = {
    'id': fields.Integer,
    'name': fields.String(attribute='username'),
    'is_active': fields.Boolean,
    'create_time': CustomDate(dt_format='iso8601'),
    'update_time': CustomDate(dt_format='strftime'),
    'address': fields.String(default='shang hai')
}

序列化后显示

代码语言:javascript
复制
{
    "code": 0,
    "msg": "success",
    "data": {
        "id": 1,
        "name": "test",
        "is_active": true,
        "create_time": "2022-09-02T10:24:48",
        "update_time": "2022-09-02 10:24:51",
        "address": "shang hai"
    }
}

网址和其他具体字段

Flask-RESTful 包含一个特殊字段 ,fields.Url它为所请求的资源合成一个 uri。这也是如何将数据添加到您的响应中的一个很好的示例,这些数据实际上并不存在于您的数据对象中。:

代码语言:javascript
复制
class RandomNumber(fields.Raw):
    def output(self, key, obj):
        return random.random()

fields = {
    'name': fields.String,
    # todo_resource is the endpoint name when you called api.add_resource()
    'uri': fields.Url('todo_resource'),
    'random': RandomNumber,
}

默认情况下fields.Url返回一个相对 uri。要生成包含方案、主机名和端口的绝对 uri,请 absolute=True在字段声明中传递关键字参数。要覆盖默认方案,请传递scheme关键字参数:

代码语言:javascript
复制
fields = {
    'uri': fields.Url('todo_resource', absolute=True),
    'https_uri': fields.Url('todo_resource', absolute=True, scheme='https')
}

2022年第 12期《python接口web自动化+测试开发》课程,9月17号开学!

本期上课时间:2022年9月17号 - 2022年12月17号,周六周日上午9:00-11:00

报名费:报名费3000一人(周期3个月)

联系微信/QQ:283340479

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2022-09-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 从零开始学自动化测试 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 模型
  • 日期字段
  • 自定义字段和多个值
  • 重命名属性
  • 默认值
  • 网址和其他具体字段
    • 报名费:报名费3000一人(周期3个月)
      • 联系微信/QQ:283340479
      相关产品与服务
      文件存储
      文件存储(Cloud File Storage,CFS)为您提供安全可靠、可扩展的共享文件存储服务。文件存储可与腾讯云服务器、容器服务、批量计算等服务搭配使用,为多个计算节点提供容量和性能可弹性扩展的高性能共享存储。腾讯云文件存储的管理界面简单、易使用,可实现对现有应用的无缝集成;按实际用量付费,为您节约成本,简化 IT 运维工作。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档