如何将API返回的空字符串转为0存入Django数据库?
解决API空字符串转整数默认值的问题
问题场景
从外部API拉取跑道数据并存入数据库时,遇到如下报错:
ValueError at /
Field 'he_displaced_threshold_ft' expected a number but got ''.
原因是API返回的JSON中,部分对应数据库IntegerField的字段为空字符串,无法直接存入数字类型字段。
相关代码
services.py
def get_runways(): params = { "apiToken": "SECRET", } api_base = "https://airportdb.io/api/v1/airport/KMIA" api_result = requests.get(api_base, params) api_response = api_result.json() for the runway in api_response["runways"]: runway_data, created = Runway.objects.update_or_create( airport_ident=Airport.objects.get(ident=runway["airport_ident"]), length_ft=runway["length_ft"], width_ft=runway["width_ft"], surface=runway["surface"], lighted=runway["lighted"], closed=runway["closed"], le_ident=runway["le_ident"], le_latitude_deg=runway["le_latitude_deg"], le_longitude_deg=runway["le_longitude_deg"], le_elevation_ft=runway["le_elevation_ft"], le_heading_degT=runway["le_heading_degT"], le_displaced_threshold_ft=runway["le_displaced_threshold_ft"], he_ident=runway["he_ident"], he_latitude_deg=runway["he_latitude_deg"], he_longitude_deg=runway["he_longitude_deg"], he_elevation_ft=runway["he_elevation_ft"], he_heading_degT=runway["he_heading_degT"], he_displaced_threshold_ft=runway["he_displaced_threshold_ft"], ) runway_data.save() return runway
models.py
class Runway(models.Model): airport_ident = models.ForeignKey(Airport, on_delete=models.CASCADE) length_ft = models.IntegerField(default=None, blank=True, null=True) width_ft = models.IntegerField(default=None, blank=True, null=True) surface = models.CharField(max_length=50, blank=True, null=True) lighted = models.IntegerField(default=None, blank=True, null=True) closed = models.PositiveBigIntegerField(default=None, blank=True, null=True) le_ident = models.CharField(max_length=5, blank=True, null=True) le_latitude_deg = models.FloatField(default=None, blank=True, null=True) le_longitude_deg = models.FloatField(default=None, blank=True, null=True) le_elevation_ft = models.IntegerField(default=None, blank=True, null=True) le_heading_degT = models.FloatField(default=None, blank=True, null=True) le_displaced_threshold_ft = models.IntegerField(blank=True, null=True) he_ident = models.CharField(max_length=5, blank=True, null=True) he_latitude_deg = models.FloatField(default=None, blank=True, null=True) he_longitude_deg = models.FloatField(default=None, blank=True, null=True) he_elevation_ft = models.IntegerField(default=None, blank=True, null=True) he_heading_degT = models.FloatField(default=0, blank=True, null=True) he_displaced_threshold_ft = models.IntegerField(default=0, blank=True, null=True) def __str__(self): return self.airport_ident.ident
解决方案
方法1:单个字段处理函数(推荐)
编写工具函数统一处理空字符串转默认值的逻辑,同时兼容非数字、None等异常情况:
def parse_to_int(value, default=0): if value == '': return default try: return int(value) except (ValueError, TypeError): return default
在update_or_create中调用该函数处理对应字段:
runway_data, created = Runway.objects.update_or_create( airport_ident=Airport.objects.get(ident=runway["airport_ident"]), length_ft=parse_to_int(runway["length_ft"]), width_ft=parse_to_int(runway["width_ft"]), surface=runway["surface"], lighted=parse_to_int(runway["lighted"]), closed=parse_to_int(runway["closed"]), le_ident=runway["le_ident"], le_latitude_deg=runway["le_latitude_deg"], le_longitude_deg=runway["le_longitude_deg"], le_elevation_ft=parse_to_int(runway["le_elevation_ft"]), le_heading_degT=runway["le_heading_degT"], le_displaced_threshold_ft=parse_to_int(runway["le_displaced_threshold_ft"]), he_ident=runway["he_ident"], he_latitude_deg=runway["he_latitude_deg"], he_longitude_deg=runway["he_longitude_deg"], he_elevation_ft=parse_to_int(runway["he_elevation_ft"]), he_heading_degT=runway["he_heading_degT"], he_displaced_threshold_ft=parse_to_int(runway["he_displaced_threshold_ft"]), )
方法2:批量处理所有整数字段
如果需要处理的字段较多,可批量遍历字典转换,减少重复代码:
def get_runways(): params = { "apiToken": "SECRET", } api_base = "https://airportdb.io/api/v1/airport/KMIA" api_result = requests.get(api_base, params) api_response = api_result.json() # 定义需要转换为整数的字段列表 int_field_names = [ 'length_ft', 'width_ft', 'lighted', 'closed', 'le_elevation_ft', 'le_displaced_threshold_ft', 'he_elevation_ft', 'he_displaced_threshold_ft' ] for runway in api_response["runways"]: # 批量处理空字符串转0 for field in int_field_names: value = runway.get(field) if value == '': runway[field] = 0 elif value is not None: try: runway[field] = int(value) except ValueError: runway[field] = 0 runway_data, created = Runway.objects.update_or_create( airport_ident=Airport.objects.get(ident=runway["airport_ident"]), **runway # 直接展开处理后的字典 ) runway_data.save() return runway
方法3:模型层处理(可选)
在模型的save方法中添加处理逻辑,但该方法仅在调用模型save时生效,update_or_create可能在验证阶段就报错,优先级低于前两种:
class Runway(models.Model): # ... 原有字段定义 ... def save(self, *args, **kwargs): # 处理需要转换的字段 int_fields = [ 'length_ft', 'width_ft', 'lighted', 'closed', 'le_elevation_ft', 'le_displaced_threshold_ft', 'he_elevation_ft', 'he_displaced_threshold_ft' ] for field in int_fields: value = getattr(self, field) if value == '': setattr(self, field, 0) elif value is not None: try: setattr(self, field, int(value)) except ValueError: setattr(self, field, 0) super().save(*args, **kwargs)
内容的提问来源于stack exchange,提问作者ejcortinas
相关产品推荐
相关产品推荐

