如何将两个Queryset合并为一个来自不同模型的Queryset?

时间:2017-10-18 20:50:33

标签: python django django-queryset models

我需要将来自不同模型的两个Queryset合并为一个。我在网上找到的建议最多的解决方案是:

使用|&,但这仅适用于来自同一模型的查询集

使用chainlist,但这会夺走一些查询集方法,并且由于我的项目中的代码的结构方式,我无法改变它。我试过了,但没有工作。

我读到Q,但我不清楚如何应用它来完成我需要的工作。

基本上我需要将来自不同模型的两个查询集合并到第三个查询集中,而不是列表。它们共享一些字段名称,或许对Q有用。例如:

queryset_1 = Cars.objects.all().filter(color='red')
queryset_2 = Horses.objects.all()

queryset_3 = queryset_1 + queryset_2

queryset_3.order_by('date')

2 个答案:

答案 0 :(得分:2)

不幸的是,您无法在数据库或查询集级别执行此操作,因为这两个内容在同一个数据库表中不存在。你可以在python方面做到这一点(虽然它更慢,计算量更大)。

假设汽车和马匹都有“日期”属性,你可以这样做:

cars = Cars.objects.all().filter(color='red')
horses = Horses.objects.all()
all_things = list(cars) + list(horses)
sorted_things = sorted(all_things, key=lambda x: x.date)

另一个选项(在数据库级别上效率低下)将使它们都从相同的非抽象模型继承。

class Item(models.Model):
    date = models.DateTimeFiedl()
    item_type = models.CharField(max_length=255)

    def get_instance(self):
        if self.item_type = 'car':
            return Car.objects.get(id=self.id)
        elif self.item_type == 'horse':
            return Horse.objects.get(id=self.id)

class Car(Item):
    color = models.CharField(max_length=12)

    def save(self, *args, **kwargs):
        self.item_type = 'car'
        super(Car, self).save(*args, **kwargs)

class Horse(Item):
    breed = models.CharField(max_length=25)

    def save(self, *args, **kwargs):
        self.item_type = 'horse'
        super(Horse, self).save(*args, **kwargs)

有了这个,你可以做到

items = Item.objects.all().order_by('date')
for item in items:
    print(type(item))  # Always "Item"
    actual_item = item.get_instance()
    if type(actual_item) == Car:
        print("I am a car")
    else:
        print("I am a horse")

在迭代它们的同时,根据需要抓取每个特定项目(类似于Wagtail处理页面的方式,您可以根据其父类来获取对象的便捷方法)

答案 1 :(得分:2)

如果您真的需要这样的查询集,这可能是模型设计不正确的一种症状,存在任何快速修复可能比重新处理模型更加繁琐的风险。我的建议是建立一个单独的模型来取代Car和Horse(即使某些字段对于每个案例的实例仍然是空的),还有一个单独的字段,以便您轻松识别这两个字段。例如:

class Vehicle(models.Model):
    category = models.IntegerField(
        choices=[(10, 'Horse'), (20, 'Car'), (30, 'Bicycle')]
    )
    # other fields here...
相关问题