如何存储用户可自定义的查询?

时间:2018-01-01 19:30:54

标签: django python-3.5

我想允许一大堆用户运行任意和定期的查询。

到目前为止,我已设法创建此模型:

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),代码对于制作而言太危险了,无论我在调用此函数之前做了多少次测试,我都不会感到安全。关于如何以干净的方式达到这个目的的任何建议?

1 个答案:

答案 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更安全,你必须检查模块的路径或模型是否存在以避免抛出ModuleNotFoundErrorImportError if< Python 3.6)或AttributeError