我们目前正在使用以下配置运行,以避免其他问题。
因此,对于这个问题:让我们假设这是必须的,并且我们不能更改Models部分。

最初,我们有以下模型:

class A(Model):
    b = ForeignKey(B)
    ... set of fields ...

class B(Model):
    ...

然后,我们添加了以下内容:
class AVer2(Model):
    b = ForeignKey(B)
    ... ANOTHER set of fields ...

假设type B的对象只能由AAVer2 引用,但不能同时由引用:

有没有一种方法可以在B上运行查询,该查询将在运行时在查询结果中返回引用该对象的正确对象类型(并且查询中同时包含这两种类型)?

您可以假定类型B的对象包含有关谁在引用它的信息。

为此,我试图避免进行昂贵的整个系统代码更改。

编辑:
显然,我的问题不清楚。因此,我将尝试更好地解释它。我得到的答案很好,但是显然我错过了问题的关键点,所以就在这里。假设我有上面的模型B,并且得到了一些对象:
b_filter = B.objects.filter(some_of_them_have_this_true=True)

现在,我想获得一个在A和AVer2中都包含一个字段的字段,其中一个过滤器进入一个值列表。因此,例如,我想获取一个名为“MyVal”的字段(A和AVer2都有),我不在乎实际的类型是什么。所以我想写一些类似的东西:
b_filter.values(['a__myval', 'aver2__myval'])

并得到如下所示的信息:[{'myval':}]
相反,我目前得到了[{'a__myval':,'aver2__myval':None}]

我希望情况更清楚。

谢谢!

最佳答案

简短的回答:您无法满足您的确切需求。

长答案:当我读到您的问题时,我想到的第一件事是Content TypesGeneric Foreign Keys and Generic Relations

无论您将使用“普通”外键还是“通用外键”(与“通用关系”结合使用),您的B实例都将同时具有A fieldAVer2 field,而这种自然的事物将使生活更轻松,并使您的目标变得更容易(B实例具有一个可能是A或Avr2)无法访问。在这里,您还应该覆盖B model save method,以强制其仅将A字段和Avr2设置为None或将A设置为None并将Avr2使用。而且,如果这样做,请不要忘记将null=True, blank=True添加到A和Avr2外键字段。

另一方面,架构的相反之处使您可以实现目标:B模型引用AAvr2,这意味着B模型对generic foreign keyA都具有一个Avr2,如下所示:(此代码在Django 1.8中,对于Django 1.9或更高版本,GenericRelation的导入,GenericForeignKey已更改)

from django.db import models
from django.contrib.contenttypes.generic import GenericRelation, GenericForeignKey
from django.contrib.contenttypes.models import ContentType


class B(models.Model):
    # Some of your fields here...
    content_type = models.ForeignKey(ContentType, null=True, blank=True)
    object_id = models.PositiveIntegerField(null=True, blank=True)
    # Generic relational field will be associed to diffrent models like A or Avr2
    content_object = GenericForeignKey('content_type', 'object_id')


class A(models.Model):
    # Some of your fields here...
    the_common_field = models.BooleanField()
    bbb = GenericRelation(B, related_query_name="a")  # since it is a foreign key, this may be one or many objects refernced (One-To-Many)


class Avr2(models.Model):
    # Some of your fields here...
    the_common_field = models.BooleanField()
    bbb = GenericRelation(B, related_query_name="avr2")  # since it is a foreign key, this may be one or many objects refernced (One-To-Many)

现在,A和Avr2都具有作为B实例的“bbb”字段。
a = A(some fields initializations)
a.save()
b = B(some fields initializations)
b.save()
a.bbb = [b]
a.save()

现在您可以执行a.bbb并获得B实例

然后像这样从A中获取Avr2b:
b.content_object  # which will return an `A object` or an `Avr2 object`

现在让我们回到您的目标:
  • 是否可以在B上运行查询,该查询将在运行时在查询结果中返回引用该对象的正确对象类型(并且查询中同时包含两种类型)?

  • 是:像这样:
    B.objects.get(id=1).content_type  # will return A or Avr2
    
  • 您想执行以下操作:b_filter = B.objects.filter(some_of_them_have_this_true=True):

    从django.db.models导入Q

    过滤器= Q(a__common_field = True)| Q(avr2__common_field = True)

    B.objects.filter(filter)
  • 因为要求[{'a__myval': , 'aver2__myval': None}]提供两个字段值,所以获取values是100%正常的。解决此问题的一种方法是获取两个干净的查询,然后将它们链接在一起,如下所示:

    从itertools进口链

    c1 = B.objects.filter(content_type__model ='a')。values('a__common_field')

    c2 = B.objects.filter(content_type__model ='avr2')。values('avr2__common_field')
    result_list = list(chain(c1, c2))
    

  • 请注意,当我们向通用关系添加related_query_name时,可以从a实例访问avr2B,这不是默认情况。

    和瞧!我希望这有帮助 !

    10-08 11:43