【问题标题】:Concatenate two QuerySets连接两个查询集
【发布时间】:2012-04-08 01:37:59
【问题描述】:

我有以下两种型号:

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()

我将如何连接一个查询集,基本上将以下内容组合成一个 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')

【问题讨论】:

    标签: sql django django-models


    【解决方案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
    

    【讨论】:

      【解决方案2】:

      更新

      刚刚找到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 之类的 DB 后端,您可能希望通过 using trick 包装查询集以减少内存占用。

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

      【讨论】:

        猜你喜欢
        • 2020-03-25
        • 2018-03-06
        • 2023-03-28
        • 2014-12-09
        • 2013-06-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多