2015-06-04 53 views
0

我一直停留在這個有一段時間了。我的問題是我需要能夠使用marshal_with並驗證來自POST的嵌套字段。我的測試是這樣的:燒瓶寧靜,marshal_with +嵌套數據

def test_user_can_apply_with_multiple_dogs(self): 

    data = { 
     # User data 
     'registration_type': "guest", 
     'first_name': 'Alex', 
     'last_name': 'Daro', 
     'phone_number': '805-910-9198', 
     'street': '13950 NW Passage', 
     'street2': '#208', 
     'city': 'Marina del Rey', 
     'state': 'CA', 
     'zipcode': '90292', 
     'photo': 'test_image.png', 
     'how_did_you_hear': 0, 
     #Dog data 
     'pets': [ 
      { 
       'dog_photo': "dog.png", 
       'name': 'Genghis Khan', 
       'breed': 'Shih Tzu', 
       'age': 'Puppy', 
       'size': 'Small', 
      }, 
      { 
       'dog_photo': "dog2.png", 
       'name': 'Archibald', 
       'breed': 'Great Dane', 
       'age': 'Adult', 
       'size': 'Extra Large', 
      }, 
     ] 
    } 

    resp = self.client.post('/profile/registration', data=json.dumps(data)) 
    self.assertEqual(resp.status_code, 200) 

和我的端點類看起來是這樣的:

nested_fields = { 
    'dog_photo': fields.String, 
    'name': fields.String, 
    'breed': fields.String, 
    'age': fields.String, 
    'size': fields.String, 
} 

profile_fields = { 
    # 'user_email':fields.String, 
    'token': fields.String, 
    'registration_type': fields.String, 
    'first_name': fields.String, 
    'last_name': fields.String, 
    'phone_number': fields.String, 
    'street': fields.String, 
    'street2': fields.String, 
    'city': fields.String, 
    'state': fields.String, 
    'zipcode': fields.Integer, 
    'photo': fields.String, 
    'how_did_you_hear': fields.String, 
    #Dog data 
    'pets': fields.Nested(nested_fields) 

} 
class GuestProfile(Resource): 
    @marshal_with(profile_fields) 
    def post(self): 
     # User data 
     parser = reqparse.RequestParser() 
     parser.add_argument('registration_type', type=str) 
     parser.add_argument('first_name', type=str, required=True, help="First Name cannot be blank.") 
     parser.add_argument('last_name', type=str, required=True, help="Last Name cannot be blank.") 
     parser.add_argument('phone_number', type=str, required=True, help="Phone Number cannot be blank.") 
     parser.add_argument('street', type=str, required=True, help="Street cannot be blank.") 
     parser.add_argument('street2', type=str) 
     parser.add_argument('city', type=str, required=True, help="City cannot be blank.") 
     parser.add_argument('state', type=str, required=True, help="State cannot be blank.") 
     parser.add_argument('zipcode', type=str, required=True, help="Zipcode cannot be blank.") 
     parser.add_argument('photo', type=str, required=True, help="Please select a photo.") 
     parser.add_argument('how_did_you_hear', type=str, required=True, help="How did you hear about us cannot be " 
                       "blank.") 
     parser.add_argument('pets', type=str) 
     kwargs = parser.parse_args() 
     print kwargs, "KWWW" 

kwargs [ '寵物']總是在爲None。有人有主意嗎?

+0

應停止使用'型= str'。我通過打印語句收集您使用Python 2,因此您的解析器將無法處理unicode。如果完全刪除'type'參數,則默認類型將是一個unicode字符串。 – Josh

+0

@Josh謝謝你的評論,這是有道理的,但它似乎沒有幫助。你是否知道任何一個使用marshal_with/reqparse和嵌套對象列表的例子/文檔? –

+0

您也可以通過不爲每個請求實例化一個新的'RequestParser'來清理代碼。將它們放在模塊級別是完全正確的。 – Josh

回答

2

Here's an example in the docs of how to make a custom parser type.

基本上,你定義一個函數:

  • 注意到參數的原始值從請求拉
  • 引發ValueError如果解析或驗證失敗
  • 返回參數如果驗證suceeds您問題相關的

基本例如:

def pet_list_parser(pets): 
    if type(pets) != list: 
     raise ValueError('Expected a list!') 

    # Do your validation of the pet objects here. For example: 
    for pet in pets: 
     if 'name' not in pet: 
      raise ValueError('Pet name is required') 

     # Also do any conversion of data types here 
     pet['name'] = pet['name'].capitalize() 

    return pets 

parser = RequestParser() 
parser.add_argument('pets', type=pet_list_parser) 

正如你可能已經猜到,這得到klunky和惱人的相當快。 Flask-RESTful中的請求解析不用於處理嵌套數據。它適用於querystring參數,頭文件,基本的JSON等,並且可以配置爲處理嵌套數據。然而,如果你要做很多事情,那麼可以省去一些麻煩,看看Marshmallow這樣的編組庫。

+0

謝謝@Josh。將最有可能與棉花糖一起。 –

+0

我的設置有一個問題。進入pet_list_parser的寵物arg作爲字典進入,而不是列表。我的'profile_fields'對你來說看起來是否正確,特別是'pets':fields.Nested(nested_fields)'line? –

+1

查看@ junnytony建議使用''pets':fields.List(fields.Nested(nested_fields))'(你沒有明確地在你的代碼中說你需要一個對象列表) – Josh

1

你錯過「的Content-Type」頭和也是action='append'爲您的寵物參數描述here

我測試上面只是增加了「的Content-Type」和行動規定的代碼,它工作在兩個Python的2.7和3

現在的問題是,它返回指定因爲字符串列表你寵物的論點爲type=str。爲了得到一個列表,你必須編寫一個自定義的解析器類型(正如@Josh所指出的那樣)。見下面的例子:

例。

def pet_parser(pet): 
    # You can do other things here too as suggested in @Josh's repsonse 
    return pet 

在資源:

parser.add_argument('pets', type=pet_parser, action='append') 

並在測試功能:

headers = [('Content-Type', 'application/json')] 
self.client.post('url', data=data, headers=headers) 
+0

感謝@ junnytony的答覆,雖然,這似乎沒有幫助。你是否知道任何一個使用marshal_with/reqparse和嵌套對象列表的例子/文檔? –

+0

@DirkDigler。這種方式沒有幫助?如果你更具體,我可能會提供一個可以幫助你更好的答案。看到我上面的編輯。 – junnytony

+0

請參閱下面的@ Josh的答案。似乎你的編輯更多的是我正在尋找的東西。 –