python - API中缺少JSON字段时的防御条件

标签 python json api mongoengine

我正在开发一个小型Python脚本,以便从forecast.io获取天气数据。一旦获得JSON文档,我就调用一个类来创建要保存在数据库中的新记录。问题是某些字段(也是我的类中的属性)并不总是在 API 中通知,因此我必须包含某种防御代码,否则当找不到字段时脚本将中断。

我找到了 @Alex Martelli 的这个答案,看起来不错:Reading from Python dict if key might not be present

If you want to do something different than using a default value (say, skip the printing completely when the key is absent), then you need a bit more structure, i.e., either:

for r in results:
    if 'key_name' in r:
        print r['key_name'] 

or

for r in results:
    try: print r['key_name']
    except KeyError: pass

但是我想知道是否必须在我想要保存的每个字段上包含“如果”或“尝试”,或者是否有更好的方法来做到这一点? (我想保存27个字段,27个“if”看起来很难看)

这是我到目前为止的代码:

from datetime import datetime

import tornado.web
import tornado.httpclient
from tornado import gen

from src.db.city import list_cities
from src.db.weather import Weather

from motorengine import *


@gen.coroutine
def forecastio_api():
    http_client = tornado.httpclient.AsyncHTTPClient()
    base_url = "https://api.forecast.io/forecast/APIKEY"
    city yield list_cities()
    for city in city:
        url = base_url + "/%s,%s" %(str(city.loc[0]), str(city.loc[1]))
        response = yield http_client.fetch(url)
        json = tornado.escape.json_decode(response.body)
        for day in json['daily']['data']:
            weather = Weather(city=city,
                              time = datetime.fromtimestamp(day['time']),
                              summary = day.get('summary'),
                              icon = day.get('icon'),
                              sunrise_time = datetime.fromtimestamp(day.get('sunriseTime')),
                              sunset_time = datetime.fromtimestamp(day.get('sunsetTime')),
                              moon_phase = day.get('moonPhase'),
                              precip_intensity = day.get('precipIntensity'),
                              precip_intensity_max = day.get('precipIntensityMax'),
                              precip_intensity_max_time = datetime.fromtimestamp(day.get('precipIntensityMaxTime')),
                              precip_probability = day.get('precipProbability'),
                              precip_type = day.get('precipType'),
                              temperature_min = day.get('temperatureMin'),
                              temperature_min_time = datetime.fromtimestamp(day.get('temperatureMinTime')),
                              temperature_max = day.get('temperatureMax'),
                              temperature_max_time = datetime.fromtimestamp(day.get('temperatureMaxTime')),
                              apparent_temperature_min = day.get('apparentTemperatureMin'),
                              apparent_temperature_min_time = datetime.fromtimestamp(day.get('apparentTemperatureMinTime')),
                              apparent_temperature_max = day.get('apparentTemperatureMax'),
                              apparent_temperature_max_time = datetime.fromtimestamp(day.get('apparentTemperatureMaxTime')),
                              dew_point = day.get('dewPoint'),
                              humidity = day.get('humidity'),
                              wind_speed = day.get('windSpeed'),
                              wind_bearing = day.get('windBearing'),
                              visibility = day.get('visibility'),
                              cloud_cover = day.get('cloudCover'),
                              pressure = day.get('pressure'),
                              ozone = day.get('ozone')
            )
            weather.create()


if __name__ == '__main__':
    io_loop = tornado.ioloop.IOLoop.instance()
    connect("DATABASE", host="localhost", port=27017, io_loop=io_loop)
    forecastio_api()
    io_loop.start()

这是使用 Motornegine 的天气类:

from tornado import gen
from motorengine import Document
from motorengine.fields import DateTimeField, DecimalField, ReferenceField, StringField

from src.db.city import City


class Weather(Document):
    __collection__ = 'weather'
    __lazy__ = False
    city = ReferenceField(reference_document_type=City)
    time = DateTimeField(required=True)
    summary = StringField()
    icon = StringField()
    sunrise_time = DateTimeField()
    sunset_time = DateTimeField()
    moon_phase = DecimalField(precision=2)
    precip_intensity = DecimalField(precision=4)
    precip_intensity_max = DecimalField(precision=4)
    precip_intensity_max_time = DateTimeField()
    precip_probability = DecimalField(precision=2)
    precip_type = StringField()
    temperature_min = DecimalField(precision=2)
    temperature_min_time = DateTimeField()
    temperature_max = DecimalField(precision=2)
    temperature_max_time = DateTimeField()
    apparent_temperature_min = DecimalField(precision=2)
    apparent_temperature_min_time = DateTimeField()
    apparent_temperature_max = DecimalField(precision=2)
    apparent_temperature_max_time = DateTimeField()
    dew_point = DecimalField(precision=2)
    humidity = DecimalField(precision=2)
    wind_speed = DecimalField(precision=2)
    wind_bearing = DecimalField(precision=2)
    visibility = DecimalField(precision=2)
    cloud_cover = DecimalField(precision=2)
    pressure = DecimalField(precision=2)
    ozone = DecimalField(precision=2)
    create_time = DateTimeField(auto_now_on_insert=True)

    @gen.coroutine
    def create(self):
        yield self.save()

最佳答案

您可以查看Schematics 。这个库可以帮助您定义可以轻松地从 dict 填充的对象(您可以轻松地将 json 转换为 python dict)。它允许您定义每个属性的验证规则。当某些属性丢失或格式错误时,该对象将抛出 ModelValidationError 错误。 Schematics 允许您在定义模型时添加默认值和更多好东西。

关于python - API中缺少JSON字段时的防御条件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34661778/

相关文章:

python - 在 Python 中使用 XMLRPC 时,尽管添加了allow_none=True,但仍出现错误 "cannot marshal None"

ios - NSJSONSerialization 不工作,NSUTF8StringEncoding 工作

javascript - 通过循环从 JSON 选择适当的单选按钮

angularjs - 使用Angularjs显示youtube api v3标题和缩略图

python - 对Django中的ForeignKey模型关系感到困惑

python - 如何在 Python 中将 CSV 转换为嵌套 JSON(最高级别 3)

java - HttpClient.execute 抛出 OutOfMemoryError

json - 分片大小的 Elasticsearch GET API

java - 带分页的 API 的 Stream 与 Iterator

Python 错误 - 或者我的愚蠢 - 在扫描字符串文字时 EOL