连接两个QuerySet

时间:2012-04-08 01:37:59

标签: sql django django-models

我有以下两种模式:

class JobPosition(models.Model):
    job = models.ForeignKey(Job, related_name='positions')
    position = models.ForeignKey('userprofile.Position')
    date_added = models.DateTimeField()
    end_date = models.DateTimeField()

class ExternalJob(models.Model):
    name = models.CharField(max_length=256)
    position = models.ForeignKey('userprofile.Position') 
    date_added = models.DateTimeField()
    end_date = models.DateTimeField()

如何连接Queryset,基本上将以下内容合并为一个QS?

internal_jobs = JobPosition.objects.filter(end_date__gte=datetime.now())
external_jobs = ExternalJob.objects.filter(end_date__gte=datetime.now())
all_jobs = (internal_jobs + external_jobs).order_by('-date_added')

2 个答案:

答案 0 :(得分:1)

首先看看这个类似的问题是否对您有所帮助:Using django how can I combine two queries from separate models into one query?。这可能是你为了追加另一个SQL语句而必须做的方法(虽然我不确定它是否可以在SQL端做你所要求的)

如果您想要实现的只是这两个查询集的惰性评估组合,那么您可以使用itertools.chain:

from itertools import chain

combined = chain(internal_jobs, external_jobs)
# combined is a generator that will iterate over your combined
# iteratables
for result in combined:
    # do something

我认为对于最终日期排序,您可能必须在客户端执行此操作。执行sorted调用时,将评估完整的查询集列表。

from operator import attrgetter

combined = chain(internal_jobs, external_jobs)
for result in sorted(combined, key=attrgetter("date_added"), reverse=True):
    # do something

答案 1 :(得分:0)

更新

刚刚找到How to combine 2 or more querysets in a Django view?,为正常情况引用它


如果性能很关键并且结果用作迭代器,则下面是jdi发布的链接中https://stackoverflow.com/a/313149/165603的更简单版本

def merge_by_latest_date_added(*querysets):
    querysets = [[qs, None] for qs in querysets]

    def iterator_helper():
        for qs_v in querysets[:]:
            qs, v = qs_v
            if v is not None:
                continue
            try:
                qs_v[1] = qs.next()
            except StopIteration:
                querysets.remove(qs_v)
        return querysets

    while iterator_helper():
        qs_v = max(querysets, key=lambda x:x[1].date_added)
        yield qs_v[1]
        qs_v[1] = None

然后你可以

internal_jobs = internal_jobs.order_by('-date_added').iterator()
external_jobs = externals_jobs.order_by('-date_added').iterator()
all_jobs = merge_by_latest_date_added(internal_jobs, external_jobs)

对于像psycopg2这样的数据库后端,您可能希望用using trick包装查询集以减少内存占用。

您还可以在while语句中隔离代码,以使合并功能成为通用版本。例如,我用它来处理在实践中共享PK的大型查询集。