我正在尝试为我的django应用程序的powerusers公开一个非常灵活的查询接口,我需要找到针对嵌入的模型层次结构过滤给定模型的各种方法。
我有一套深层嵌套的模型:
from django.db import models
class City(models.Model):
name = models.CharField(max_length=15)
class Team(models.Model):
location = models.ForeignKey(City)
name = models.CharField(max_length=15)
class Employee(models.Model):
teams = models.ManyToManyField(Team)
location = models.ForeignKey(City)
class Task(models.Model):
assignee = models.ForeignKey(Employee)
使用querysets我可以构建一个复杂的查询,例如查找分配给慕尼黑员工的所有任务:
tasks = Task.objects.filter(assignee__location="Munich")
或更复杂的事情,通过M2M:
tasks = Task.objects.filter(assignee__teams__location__="Munich")
我想引导用户完成构建有意义的复杂查询的过程,并希望显示他们过滤模型Task
的所有选择,因此我提出了这个算法:
def traverse(waiting,result=list(),grave=set()):
if not waiting:
# If there is nothing waiting we are done
return
objekt, prefix = waiting.pop(0) # Remove an item from the front of the queue
SEPARATION_CHARACTER = "__" #django uses __ instead of . in query strings
newprefix=prefix
if prefix:
newprefix = prefix +SEPARATION_CHARACTER
try:
modelname = objekt._meta.object_name
if modelname in grave:
# If the current model name is in the graveyard, it has been touched by another
# chain and doesn't need to be processed.
return
# We now know we are dealing with a complex object that may have fields
grave.add(objekt._meta.object_name)
fields = objekt._meta.get_all_field_names()
for field in fields:
# For every attribute of the field, create a new tuple in waiting
try:
waiting.append((getattr(objekt,field),newprefix+field))
except:
pass
for field in fields:
traverse(waiting, result, grave)
except:
# If objekt._meta doesn't exist, the thing is not a complex object and we can stop this chain.
# add the fully qualified path to the result
result.append(prefix)
return result
这将按照ForeignKey
s成功找到给定模型的所有过滤器可能性,但会在反向ForeignKey
和ManyToManyField
s上停止。
如何扩展算法以向我提供所有可能的过滤器选项?