<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                [TOC] ## 第4章 自定義異常對象 ### 4-1 關于“用戶”的思考 ### 4-2 構建 Client 驗證器 1. 我們使用枚舉類型來代表不同的客戶端 ~~~ ?from enum import Enum ?? ?? ?class ClientTypeEnum(Enum): ? ? ?USER_EMAIL = 100 ? ? ?USER_MOBILE = 101 ?? ? ? ?# 微信小程序 ? ? ?USER_MINA = 200 ? ? ?# 微信公眾號 ? ? ?USER_WX = 201 ~~~ 2. 然后再編寫自定義的驗證器驗證客戶端傳入過來的**客戶端類型**,先將客戶端傳入過來的數字轉換成枚舉類型 * 如果轉換成功,則表示客戶端傳入進來的數字是正確的 * 如果轉換不成功則會報錯,表示客戶端傳入的數字是錯誤的 ~~~ ?class ClientForm(Form): ? ? ?account = StringField(validators=[DataRequired(), length(min=8, max=32)]) ? ? ?secret = StringField() ? ? ?type = IntegerField(validators=[DataRequired()]) ?? ? ? ?def validate_type(self, value): ? ? ? ? ?""" ? ? ? ? 這里自定義的驗證器方法名必須為 'validate_' + 字段名(類變量) ? ? ? ? 因為 flask 內部設定的,只有這樣寫才會觸發該自定義的驗證器驗證 ? ? ? ? :param value: type 傳入的具體字段,是 flask 調用驗證器的時候自動傳入的 ? ? ? ? :return: 如果在自定義的驗證器內拋出異常則表示驗證失敗;不拋出異常,則表示驗證成功(暫時是這么理解的) ? ? ? ? """ ? ? ? ? ?from app.libs.enums import ClientTypeEnum ? ? ? ? ?try: ? ? ? ? ? ? ?client = ClientTypeEnum(value.data) ? ? ? ? ?except ValueError as e: ? ? ? ? ? ? ?raise e ? ? ? ? ?self.type.data = client ~~~ **注意**:(查看 `validate_for_api()` 源碼發現的) * 這里自定義的驗證器方法名必須為 `'validate_' + 字段名`(類變量) * 因為 flask 內部設定的,只有這樣寫才會觸發該自定義的驗證器驗證 * `:param value:` type 傳入的具體字段,是 flask 調用驗證器的時候自動傳入的 * `:return:` 如果在自定義的驗證器內拋出異常則表示驗證失敗;不拋出異常,則表示驗證成功(暫時是這么理解的) * 另外在 pycharm 中會提示 `validate_type`為靜態方法,但是實際上這種自定義的驗證器方法是實例方法。絕對不能改為靜態方法,否則會報錯,因為在 `flask` 內部調用的時候是使用 `ClientForm`、`UserEmailForm`、`UserMobileForm`等的實例來調用自定義的驗證器的。 ![](https://ws1.sinaimg.cn/large/006tNc79gy1fzgbbz4luyj328k0n87ae.jpg) > 小技巧: > > 在獲取客戶端傳入的數字時,單純的使用的 value 是獲取不到信息的,需要使用 **value.data** 上述代碼的精妙之處在于兩點: * 我們可以去判斷客戶端穿過來的數字是否是我們枚舉類型的一種 * 客戶端傳過來的是一個數字的值,但是在我們整個代碼編寫過程中我們并不希望直接使用數字,因為我們已經定義了枚舉類型,所以我們更加希望在項目中使用枚舉,因為枚舉的可讀性比數字要強。 ### 4-3 處理不同客戶端注冊的方案 #### 提交數據 客戶端向服務器發送數據的兩種不同的形式: * 表單:通常用于網頁中 * JSON 對象:移動端 #### 接收數據 服務器接收參數的方式有兩類: * `request.json` (`request.get_json(salient=True)`) * `request.args.to_dict()` 具體的區別稍后再說,我們先使用 request.json 來寫: ~~~ ?data = request.json # 接收到 data ?form = ClientForm(data=data) ~~~ 先使用 request.json 接收到 data,然后實例化一個`form`,這個 `form`就是 `ClientForm`。 下面要考慮的就是如何將 data 參數傳入 `ClientForm`中,然后 `ClientForm`才能執行校驗。我們在**Flask高級編程**中傳遞客戶端的參數是直接把數據放到 `ClientForm`的必填參數中傳遞進來的。但是如果數據是 JSON 格式的話,就需要使用 `ClientForm`的關鍵字參數`data=`傳參。 > 這種傳參方式需要深入挖掘 wtforms 的源碼才會知道。 如果數據驗證通過的話,就可以進行注冊了。但是由于客戶端的種類是不同的,不同客戶端的注冊代碼也是不同的。在其他語言中可以使用`switch case`為不用的客戶端編寫不同的注冊代碼,但是 python 中是沒有 `switch`的,所以需要一些小技巧。 可以使用字典的方式解決。解決方式: ~~~ ?promise = { ? ? ? ? ? ? ?ClientTypeEnum.USER_EMAIL: __register_by_email, ? ? ? ? ? ? ?ClientTypeEnum.USER_MOBILE: __register_by_mobile, ? ? ? ? ? ? ?ClientTypeEnum.USER_MINA: __register_by_mina, ? ? ? ? ? ? ?ClientTypeEnum.USER_WX: __register_by_wx, ? ? ? ? } ~~~ 構造字典:{客戶端類型:該類型的注冊函數} 調用注冊函數的方式: ~~~ ?promise[form.type.data]() ~~~ ### 4-4 創建 User 模型 ~~~ ?from sqlalchemy import Column, Integer, String, SmallInteger ?from werkzeug.security import generate_password_hash ?? ?from app.models.base import Base, db ?? ?? ?class User(Base): ? ? ?id = Column(Integer, primary_key=True) ? ? ?email = Column(String(24), unique=True, nullable=False) ? ? ?nickname = Column(String(24), unique=True) ? ? ?auth = Column(SmallInteger, default=1) ? ? ?_password = Column('password', String(128)) ?? ? ? ?@property ? ? ?def password(self): ? ? ? ? ?return self._password ?? ? ? ?@password.setter ? ? ?def password(self, raw): ? ? ? ? ?self._password = generate_password_hash(raw) ?? ? ? ?@staticmethod ? ? ?def register_by_email(nickname, account, secret): ? ? ? ? ?with db.auto_commit(): ? ? ? ? ? ? ?user = User() ? ? ? ? ? ? ?user.nickname = nickname ? ? ? ? ? ? ?user.email = account ? ? ? ? ? ? ?user.password = secret ? ? ? ? ? ? ?db.session.add(user) ~~~ 上面`User`模型的`register_by_email`方法中實例化了 `user`,我們在 `User`對象內部又創建了這個對象本身,從面向對象的角度來說這是不合理的,但是如果該方法是**靜態方法**或者**類方法**的話,那么就可以說得通了。靜態方法就是跟類、示例無關的方法。類方法就是類的方法,類方法當然可以生成類的實例對象。 ### 4-5 完成客戶端注冊 ### 4-6 生成用戶數據 ### 4-7 自定義異常對象 ![](https://ws4.sinaimg.cn/large/006tNbRwgy1fyqwy1io2vj31hb0o144h.jpg) 我們在 ginger/app/libs/error\_code.py 中自定義異常,在 client.py 中調用就可以了,拋出異常僅僅只是為了顯示出程序運行的錯誤信息而已,并沒有其他操作。此處繼承的是 APIException 不是 HTTPException。 ~~~ ?class ClientTypeError(APIException): ? ? ?# 400 401 403 404 ? ? ?# 500 ? ? ?# 200 201 204 ? ? ?# 301 302 ? ? ?code = 400 ? ? ?msg = 'client is invalid' ? ? ?error_code = 1006 ~~~ 結果如下所示: ![](https://ws4.sinaimg.cn/large/006tNbRwgy1fyqx39n0d1j32ji0rate5.jpg) ### 4-8 淺談異常返回的標準與重要性 ![](https://ws4.sinaimg.cn/large/006tNbRwgy1fyqxc7t207j327p0rx0ye.jpg) **一個 API 寫的好不好關鍵就在于你的錯誤異常信息的表示和描述是否準確、格式是否規范、是否有一個統一的標準。** ### 4-9 自定義APIException 自定義的 APIException 需要繼承 HTTPException,同時需要覆寫 get\_body、get\_headers 方法,編寫 get\_url\_no\_param 方法獲取當前訪問的不含查詢參數的 url。 ~~~ ?from flask import request, json ?from werkzeug.exceptions import HTTPException ?? ?? ?? ?class APIException(HTTPException): ? ? ?code = 500 ? ? ?msg = 'sorry, we made a mistake (* ̄︶ ̄)!' ? ? ?error_code = 999 ?? ? ? ?def __init__(self, msg=None, code=None, error_code=None, ? ? ? ? ? ? ? ? ? headers=None): ? ? ? ? ?if code: ? ? ? ? ? ? ?self.code = code ? ? ? ? ?if error_code: ? ? ? ? ? ? ?self.error_code = error_code ? ? ? ? ?if msg: ? ? ? ? ? ? ?self.msg = msg ? ? ? ? ?super(APIException, self).__init__(msg, None) ?? ? ? ?def get_body(self, environ=None): ? ? ? ? ?body = dict( ? ? ? ? ? ? ?msg=self.msg, ? ? ? ? ? ? ?error_code=self.error_code, ? ? ? ? ? ? ?request=request.method + ' ' + self.get_url_no_param() ? ? ? ? ) ? ? ? ? ?text = json.dumps(body) ? ? ? ? ?return text ?? ? ? ?def get_headers(self, environ=None): ? ? ? ? ?"""Get a list of headers.""" ? ? ? ? ?return [('Content-Type', 'application/json')] ?? ? ? ?@staticmethod ? ? ?def get_url_no_param(): ? ? ? ? ?full_path = str(request.full_path) ? ? ? ? ?main_path = full_path.split('?') ? ? ? ? ?return main_path[0] ~~~ 字典轉化為文本,采用 `json`序列化的方式:`json.dumps()` > `request.full_path():` > > 獲取完整的請求路徑。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看