简体   繁体   English

如何将 Django 中的多个模型加入到虚拟表中?

[英]How can I join multiple models in Django into a virtual table?

If I have 3 models, like:如果我有 3 个模型,例如:

class Cow(models.Model):
    name =
    number_of_eyes =
    number_of_feet =
    color =

class Pig(models.Model):
    name =
    number_of_eyes = 
    number_of_feet =
    intelligence = 
    
class Horse(models.Model):
    name =
    number_of_eyes =
    number_of_hooves = 
    weight_capacity =
    speed =

And I'm interested in making a single Livestock table in my template that has instances of all 3, but I'm only interested in these columns that all 3 models have:而且我有兴趣在我的模板中创建一个包含所有 3 个实例的Livestock表,但我只对所有 3 个模型都具有的这些列感兴趣:

  • name姓名
  • number_of_eyes number_of_eyes
  • number_of_feet (number_of_hooves if Horse) number_of_feet (number_of_hooves 如果马)

And we can ignore all other columns.我们可以忽略所有其他列。

How can I join them into a single queryset?如何将它们加入单个查询集?

The end goal is to get a single virtual table (queryset) that I can do a few other operations on (filter, order_by, slice), and then return the data in just those columns.最终目标是获得一个虚拟表(查询集),我可以对它执行一些其他操作(filter、order_by、slice),然后仅在这些列中返回数据。

Is this possible in the Django ORM?这在 Django ORM 中是否可行?

Apparently this can also be done using a Union , as suggested by Nick ODell:显然,这也可以使用Union来完成,正如 Nick ODell 所建议的:

from django.db.models import F

Cow.objects.filter(...).union(
  Pig.objects.filter(...), 
  Horse.objects.filter(...).annotate(number_of_feet=F("number_of_hooves"))
).values('name', 'number_of_eyes', 'number_of_feet').order_by('name')[:3]

Unfortunately you can't filter on the resulting queryset after the union, so you need to filter each queryset before the union, but other than that, everything seems to work in my quick test.不幸的是,您无法在联合之后过滤生成的查询集,因此您需要在联合之前过滤每个查询集,但除此之外,在我的快速测试中似乎一切正常。

From what I understand, the difference here from MojixCoder's suggestion of using ContentType is that you don't need to maintain a separate definition of this virtual table in your Django models module.据我了解,这里与 MojixCoder 建议使用ContentType的区别在于,您不需要在 Django 模型模块中维护此虚拟表的单独定义。 In some cases, that can be an advantage, as you don't need to keep the module updated when you get new models you want to include in your query, but in other cases, it can be a disadvantage, because my way has a lot of typing every time you want to use this query, whereas in MojixCoder's example, you define it once, and your queries would be much shorter.在某些情况下,这可能是一个优势,因为当您获得要包含在查询中的新模型时,您不需要保持模块更新,但在其他情况下,这可能是一个劣势,因为我的方式有每次你想使用这个查询时都要输入很多,而在 MojixCoder 的例子中,你定义一次,你的查询会更短。

I think you have two options:我认为你有两个选择:

  1. using itertools.chain :使用itertools.chain

     from itertools import chain cows = Cow.objects.all() pigs = Pig.objects.all() horses = Horse.objects.all() livestock_list = sorted( chain(cows, pigs, horses), key=lambda livestock: livestock.created_at, reverse=True) )
  2. using contenttypes :使用contenttypes

     from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.fields import GenericForeignKey class Livestock(models.Model): content_type = models.ForeignKey(ContentType) object_id = models.PositiveIntegerField() content_object = GenericForeignKey('content_type', 'object_id') created = models.DateTimeField(auto_now_add=True) class Meta: ordering = ['-created']

    Now you can query Livestock model like any other model in Django , but you can have a foreign key that can refers to n models.现在您可以像 Django 中的任何其他 model 一样查询Livestock Django ,但是您可以有一个可以引用 n 个模型的外键。 that's what contenttypes do.这就是内容contenttypes所做的。

    Livestock.content_object gives you what you want in your case it can be Cow , Pig or Horse . Livestock.content_object为您提供您想要的东西,它可以是CowPigHorse

    Just remember to add objects to Livestock model after you create horse, etc instances.只要记住在创建马等实例后将对象添加到Livestock model 即可。 you need to add them in 2 models actually.您实际上需要将它们添加到 2 个模型中。 you can do it with signals.你可以用信号来做。

I think the second solution is better.我认为第二种解决方案更好。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM