iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 22
1

重構Resource

截至目前為止,使用者的restful已經有個初步的雛形,那接下來要做些甚麼呢?所以今天先重新檢視一下現有的程式碼,雖然昨日的課程把一些驗證請求參數的部份抽離到UserSchema內,不過user.py仍有許多改善的空間,所以今天的內容將一步一步的教授大家如何更進一步重構user.py。

本文章同步放置於此

截至目前的user.py

再接著說明如何重構之前先讓大家看看截至目前的程式碼。

from flask_restful import Resource
from flask import request
from models.schema.user import UserSchema

users = []
user_schema = UserSchema()


class User (Resource):

    def get(self, name):
        find = [item for item in users if item['name'] == name]
        if len(find) == 0:
            return {
                'message': 'username not exist!'
            }, 403
        user = find[0]
        if not user:
            return {
                'message': 'username not exist!'
            }, 403
        return {
            'message': '',
            'user': user
        }

    def post(self, name):
        result = user_schema.load(request.json)

        if len(result.errors) > 0:
            return result.errors, 433

        user = {
            'name': name,
            'email': result.data['email'],
            'password': result.data['password']
        }
        global users
        users.append(user)
        return {
            'message': 'Insert user success',
            'user': user
        }

    def put(self, name):
        result = user_schema.load(request.json)

        if len(result.errors) > 0:
            return result.errors, 433

        find = [item for item in users if item['name'] == name]
        if len(find) == 0:
            return {
                'message': 'username not exist!'
            }, 403
        user = find[0]
        user['email'] = result.data['email']
        user['password'] = result.data['password']
        return {
            'message': 'Update user success',
            'user': user
        }

    def delete(self, name):
        global users
        users = [item for item in users if item['name'] != name]
        return {
            'message': 'Delete done!'
        }


class Users(Resource):
    def get(self):
        return {
            'message': '',
            'users': users
        }

建立user.py

首先先將使用者相關的函式抽離User這個Resource,而且將users這變數也放到models.user.py內,所以我們重構的第一個步驟就是產生含有以下內容的models.user.py:


users = []


class UserModel:
    name = ''
    email = ''
    password = ''

    def __init__(self, name, email, password):
        self.name = name
        self.email = email
        self.password = password

    def add_user(self):
        users.append(self)

    @staticmethod
    def get_user(name):
        find = [item for item in users if item.name == name]
        if len(find) == 0:
            return None
        return find[0]

    @staticmethod
    def delete_user(name):
        global users
        users = [item for item in users if item.name != name]

    @staticmethod
    def get_all_user():
        return users

修改User這個Resource

在抽離使用者相關的函式之後,我們首先整理User這個Resource,簡單來說就是把相同的動作以呼叫models.user來取代,但是在返還客戶端會遇到Model解析的問題,因為我們之前的使用者資料都是返回dict格式,所以flask-restful會自動轉換為JSON格式,但是現在的使用者資料是UserModel所以返還時無法解析,這時再透過flask-marshmallow來處理即可,處理的方式如下列說明:

user_schema.dump(user).data

最後user修改後結果如下:

from flask_restful import Resource
from flask import request
from models.schema.user import UserSchema
from models.user import UserModel

user_schema = UserSchema(many=False)


class User (Resource):

    def get(self, name):
        user = UserModel.get_user(name)
        if not user:
            return {
                'message': 'username not exist!'
            }, 403
        return {
            'message': '',
            'user': user_schema.dump(user).data
        }

    def post(self, name):
        result = user_schema.load(request.json)

        if len(result.errors) > 0:
            return result.errors, 433

        user = UserModel(name, result.data['email'], result.data['password'])
        user.add_user()
        return {
            'message': 'Insert user success',
            'user': user_schema.dump(user).data
        }

    def put(self, name):
        result = user_schema.load(request.json)
        if len(result.errors) > 0:
            return result.errors, 433

        user = UserModel.get_user(name)
        if not user:
            return {
                'message': 'username not exist!'
            }, 403
        user.email = result.data['email']
        user.password = result.data['password']
        return {
            'message': 'Update user success',
            'user': user_schema.dump(user).data
        }

    def delete(self, name):
        UserModel.delete_user(name)
        return {
            'message': 'Delete done!'
        }


class Users(Resource):
    def get(self):
        return {
            'message': '',
            'users': user_schema.dump(UserModel.get_all_user(), True).data
        }

改善取得請求參數問題

在抽離公同函式之後,我們可以針對已知問題加以改善,所以這邊我們在針對POST與PUT都在處理請求參數的部分抽離共同函式來處理,而相關改善的程式碼如下所示:

def get_param():
    data = request.get_json(force=False)
    if data is None:
        data = request.form
    return data

小結

在完成使用者的CRUD後我們改進了請求參數的方式,今日又抽離共同方法,將原本的使用者Resource重構並改善其功能。接下來的工作就是導入db,讓既有的使用者資料存放在資料庫中,敬請期待。


上一篇
DAY20-搞懂如何用marshmallow解析請求參數
下一篇
DAY22-搞懂如何導入sqlite
系列文
瓶子裡裝甚麼藥,使用Flask輕輕鬆鬆打造一個RESTful API31

2 則留言

0

2019年底還在看的要使用marshmallow 2.X版本

kirai iT邦新手 5 級 ‧ 2019-09-26 21:21:56 檢舉

感謝分享

0
a820502
iT邦新手 5 級 ‧ 2020-02-15 14:55:15

版主您好,我在執行POST中
此行 result = user_schema.load(request.json) 會顯示錯誤
看起來主要原因是
marshmallow.exceptions.ValidationError: {'_schema': ['Invalid input type.']}
想請問該如何修正呢?

kirai iT邦新手 5 級 ‧ 2020-02-15 18:42:07 檢舉

你可以看一下前一篇,然後檢查一下你post的型別跟定義的是否相符

a820502 iT邦新手 5 級 ‧ 2020-02-17 22:54:55 檢舉

我都是照著文章的方式寫,基本上完全依樣
但執行還是遇到此問題
嘗試將(request.json) print出來,會是NULL

我要留言

立即登入留言