如何跨关系获取特定模型的所有可能的过滤器选项?

时间:2015-06-01 09:40:22

标签: django foreign-keys many-to-many django-queryset

我正在尝试为我的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成功找到给定模型的所有过滤器可能性,但会在反向ForeignKeyManyToManyField s上停止。

如何扩展算法以向我提供所有可能的过滤器选项?

0 个答案:

没有答案