如何在Django filter()方法中传入json_values字典过滤模型数据
Django filter方法传入字典键值对实现查询的方案
Django ORM的filter()原生支持通过**解包字典的方式传入查询条件,你持有的json_values本身就是「模型字段名-匹配值」结构的字典,直接解包传入即可完成过滤。
需要注意你原有代码里存在两处逻辑bug,会导致更新已有对象的逻辑失效,需要一并修正:
- 原代码中判断对象是否存在的
exists()调用没有传入过滤条件,会直接判断整张表是否有任意数据,不符合业务逻辑 - 原代码查询到已存在的
retrieved_object后,直接将变量重新赋值为传入的新model实例,导致之前的查询完全失效,不会更新已有数据
修正后的完整逻辑代码
def upload_object_values(model, json_values, update_if_exists=True): if json_values: # 拷贝字典避免遍历过程中修改原字典报错 valid_query_params = json_values.copy() # 移除id类字段,不作为匹配条件 for key in list(valid_query_params.keys()): if key.endswith('_id') or key == 'id': valid_query_params.pop(key) # 给传入的新实例先赋值字段 for key, value in valid_query_params.items(): setattr(model, key, value) if update_if_exists: # 解包字典传入filter,生成统一查询集 matched_queryset = model.__class__.objects.seal().filter(**valid_query_params) if matched_queryset.exists(): # 取出已存在的记录 existing_obj = matched_queryset.first() # 将新的字段值更新到已存在的记录上 for key, value in valid_query_params.items(): setattr(existing_obj, key, value) existing_obj.save() print(existing_obj) print('existing, saved successfully') else: # 无匹配记录,直接保存新实例 model.save() print('does not exist, saved successfully') else: model.save() print('created successfully')
说明
- 传入的示例数据
{'notes': '', 'name': 'test issuer', 'phone': None}解包后等价于调用.filter(notes='', name='test issuer', phone=None),Django会自动将phone=None翻译为SQL中的phone IS NULL查询,不需要额外处理空值 - 建议将过滤用的参数字典单独存为变量,避免
exists()和filter()两次调用传入的条件不一致 - 遍历字典删除键的时候,建议遍历字典的键列表副本,避免迭代过程中字典长度变化触发运行时报错
内容的提问来源于stack exchange,提问作者Prosy A.
相关产品推荐
相关产品推荐

