如何确保queryset将由有效字段django排序

如何确保queryset将由有效字段django排序,django,Django,这是模板标记代码的一部分,其中qs是查询集 def foo(qs): ... context['key'] = qs.order_by('an_invalid_field_coming_from_user') 在代码执行超出模板标记的范围之前,如何检查queryset是否按有效字段排序,而不是强制求值 代码原样不会引发错误,因为查询集未被计算qs.exists()也不是答案,因为它将不按顺序执行查询 EDIT:请注意,查询可能比我的预编辑简单示例Foo.objects.all(

这是模板标记代码的一部分,其中qs是查询集

def foo(qs):
    ...
    context['key'] = qs.order_by('an_invalid_field_coming_from_user')
在代码执行超出模板标记的范围之前,如何检查queryset是否按有效字段排序,而不是强制求值

代码原样不会引发错误,因为查询集未被计算
qs.exists()
也不是答案,因为它将不按顺序执行查询


EDIT:请注意,查询可能比我的预编辑简单示例
Foo.objects.all()
更复杂,例如,它可能具有一个导致连接的
extra()
方法。

对不存在的字段使用
order\u by()
将抛出一个
django.core.exceptions.FieldError
。只需捕获该错误并将错误报告给用户。

我不确定这是一个好主意,因为这里可能有安全方面的考虑。我认为这会起作用,但我现在没有Django的副本可以测试。我很确定在执行此操作时会引发异常,但如果您不想捕获该异常或先发制人地进行检查,则此操作应能正常工作:

if hasattr(Foo, "fieldname") and isinstance(getattr(Foo, "fieldname"), models.Field):
    print "Safe field"
else:
    print "Invalid field"

如果您确实反对捕获异常(您不应该这样做),您可以这样做:

if context['key'] in [field.name for field in Foo._meta.fields]:
    qs = Foo.objects.all().order_by(context['key'])

您可以通过运行str(qs.query)强制queryset进行验证。此时,您可以捕获异常,而不会导致它查询数据库。


我试图避免对查询求值,这样一个有效的查询就不会被执行两次——一次是现在执行,一次是以后执行。但也许我太挑剔了。没有例外,因为添加order_by不会强制进行评估。关于您的解决方案,如果queryset有一个额外的方法,并具有模型以外的其他字段,该怎么办?噢,我写错了。and后面的子句应确保该属性是某种类型的字段(因为所有类型的字段都继承models.Field)。我刚修好。希望这更有意义。我并不反对捕获异常,我正在尝试避免在templatetag中预先评估queryset,因为它没有任何用处。是的,如果queryset基于单个模型,这将起作用。如果查询是以连接为特征的复杂查询,则不会。执行查询并捕获错误似乎是最好的选择。您不是每次运行此
if
语句时都从列表理解创建列表吗?那太没效率了。对列表运行成员资格搜索(中的
)也是低效的。对字典中的一组或多个键运行成员资格搜索要高效得多。
try:
    str(qs.order_by('some_field').query)
except FieldError:
    # bad order_by
    pass