【问题标题】:How to store user customizable queries?如何存储用户可自定义的查询?
【发布时间】:2018-06-11 15:58:54
【问题描述】:

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

到目前为止,我已经成功创建了这个模型:

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),代码太危险而无法投入生产,无论在调用此函数之前我会做多少测试,我都不会对此感到安全。关于如何以干净的方式实现此目的的任何建议?

【问题讨论】:

    标签: django python-3.5


    【解决方案1】:

    您可以解压包含这些值的 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 值 将是这些参数值。

    importlib.import_module 将允许您使用字符串导入 PYTHONPATH 中的任何模块,这通常包括所有 django 应用程序路径(因此 app.models 应该不是问题)。

    这绝对比使用eval 更安全,并且您必须检查模块的路径或模型是否存在以避免抛出ModuleNotFoundError (ImportError if AttributeError。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-29
      • 2017-11-15
      • 2022-09-27
      • 2021-12-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多