我的用例是我需要将查询存储在数据库中并不时检索它们并进行评估。这是邮件应用程序所需要的,每个用户都可以订阅通过单独定制的查询选择的网站内容。最基本的解决方案是存储原始 SQL 并将其与RawQuerySet
. 但我想知道有没有更好的解决方案?
3 回答
乍一看,将查询构建工作交给其他人真的很危险,因为他们可以做任何事情(甚至删除数据库中的所有数据或删除整个表等)
即使您让他们构建查询的特定部分,它仍然对Sql Injection开放。如果所有这些危险都可以,那么您可以尝试以下方法。
这是我使用的旧脚本,让用户设置查询的特定部分。基础是使用string.Template
和eval
(邪恶的部分)
定义你的模型:
class SomeModel(Model):
usr = ForeingKey(User)
ct = ForeignKey(ContentType) # we will choose related DB table with this
extra_params = TextField() # store extra filtering criteria in here
让我们执行属于用户的所有查询。假设我们有一个User
查询extra_params
is_staff
和'username__iontains'
用户:某人
ct:用户
extra_params: is_staff=$stff_stat, username__icontains='$uname'
$
在 extra_params 中定义占位符
from string import Template
for _qry in SomeModel.objects.filter(usr='somebody'): # filter somebody's queries
cts = Template(_qry.extra_params) # take extras with Template
f_cts = cts.substitute(stff_stat=True, uname='Lennon') # sustitute placeholders with real time filtering values
# f_cts is now `is_staff=True, username__icontains='Lennon'`
qry = Template('_qry.ct.model_class().objects.filter($f_cts)') # Now, use Template again to place our extras into a django `filter` query. We also select related model in here with `_qry.ct.model_class()`
exec_qry = qry.substitute(f_cts=f_cts)
# now we have `User.objects.filter(is_staff=True, username__icontains='Lennon')
query = eval(exec_qry) # lets evaluate it!
如果您已完成所有相关导入,那么您可以在 extra_params 中使用Q
或任何其他查询构建选项。您也可以使用其他方法来形成Create
或Update
查询。
您可以在此处阅读有关Template
表单的更多信息。但正如我所说。将这样的选项提供给其他用户是非常危险的。
您还可能需要阅读有关Django 内容类型的信息
更新:正如@GillBates 提到的,您可以使用字典结构来创建查询。在这种情况下,您将不再需要Template
。您可以使用 json 进行此类数据传输(或任何其他,如果您愿意)。假设您在代码之后使用 json 从外部源获取数据是一个使用上层代码块中的一些变量的划痕。
input_data : '{"is_staff"=true, "username__icontains"="Lennon"}'
import json
_data = json.loads(input_data)
result_set = _qry.ct.model_class().objects.filter(**_data)
根据你的回答,
用户将一些特定于内容的参数传递到表单中,然后查看函数,接收 POST,构造查询
一种选择是存储参数(pickle'd 或 json'ed,或在模型中)并使用常规 django 方法重建查询。这是一个更强大的解决方案,因为它可以处理一些数据结构的变化。
您可以创建一个新模型user_option
并将选择存储在此表中。根据您的问题,很难确定它是否是一个更好的解决方案,但它会使您的用户的选择在您的数据结构中更加明确。