我想允许一大堆用户运行任意和定期的查询。
到目前为止,我已设法创建此模型:
class BasicQuery(models.Model):
id = models.AutoField(primary_key=True)
target_entity = models.CharField(max_length=255)
target_field = models.CharField(max_length=255)
operator = models.CharField(max_length=10)
compare_value = models.CharField(max_length=10)
active = models.BooleanField()
run_every = models.ForeignKey(QueryFrequency)
以及执行它的函数:
def rule_runner(rule):
target_entity = rule.target_entity
fieldname = rule.target_field
val = rule.compare_value
if rule.operator:
cmd = '{}.objects.filter({}__{}={})'.format(rule.target_entity,
rule.target_field,
rule.operator,
rule.compare_value)
else:
cmd = '{}.objects.filter({}={})'.format(rule.target_entity,
rule.target_field,
rule.compare_value)
return eval(cmd)
但由于eval(cmd)
,代码对于制作而言太危险了,无论我在调用此函数之前做了多少次测试,我都不会感到安全。关于如何以干净的方式达到这个目的的任何建议?
答案 0 :(得分:0)
您可以解压缩包含值的dict,因此可以使用filter方法动态使用它们。关于rule.target_entity
,您可以使用importlib.import_module(str)
和getattr(module, str)
来获取它:
import importlib
def rule_runer(rule):
model = getattr(importlib.import_module('app.models'), 'Model')
if rule.operator:
field = rule.target_field
else:
field = '{}__{}'.format(rule.target_field, rule.operator)
return model.objects.filter(**{field: rule.compare_value})
解压缩dict是将**
放在它之前。这可用于动态设置函数的参数,因此 dict键将是参数名称, dict值将是这些参数值。
importlib.import_module
将允许您导入PYTHONPATH
中的任何模块,其中通常包含所有django应用程序路径(因此app.models
应该不成问题),使用字符串
这比使用eval
更安全,你必须检查模块的路径或模型是否存在以避免抛出ModuleNotFoundError
(ImportError
if< Python 3.6)或AttributeError
。