Django中的多个对象类型引用

Tal*_*Tal 9 django orm django-models

我们目前正在运行以下配置以避免其他问题.
所以对于这个问题:让我们假设这是必须的,我们不能改变模型部分.

一开始我们有以下模型:

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

class B(Model):
    ...
Run Code Online (Sandbox Code Playgroud)

然后我们添加了这样的东西:

class AVer2(Model):
    b = ForeignKey(B)
    ... ANOTHER set of fields ...
Run Code Online (Sandbox Code Playgroud)

假设一个对象type B只能由两个AAVer2 两个引用:

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

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

我试图避免代价高昂的整个系统代码更改.

编辑:显然,我的问题不明确.所以我会尝试更好地解释它.我得到的答案很棒,但显然我错过了我的问题中的一个关键点,所以在这里.假设我有上面的模型B,我得到一些对象:

b_filter = B.objects.filter(some_of_them_have_this_true=True)
Run Code Online (Sandbox Code Playgroud)

现在,我希望得到A和AVer2中的一个字段,其中一个过滤器放入一个值列表中.所以例如,我想得到一个名为"MyVal"的字段(A和AVer2都有它)我不关心实际类型是什么.所以我想写一些像:

b_filter.values(['a__myval', 'aver2__myval'])
Run Code Online (Sandbox Code Playgroud)

并得到类似以下内容的回报:[{'myval':}]相反,我现在得到[{'a__myval':,'aver2__myval':无}]

我希望它更清楚.

谢谢!

Mat*_*zyk 0

我不确定你想在查询集中得到什么。

我假设您想要一组“正确的对象类型”,“其中包含两种类型”,所以实际上您想要一组相关的类类型(例如[<class 'main.models.A'>, <class 'main.models.A2'>])。如果情况并非如此,我可以在评论中提供更多具体细节后更改答案。

这是“类列表”的解决方案,您可以使用它来获得您想要的东西。

# Our custom QuerySet that with function that returns list of classes related to given B objects
class CustomQuerySet(models.QuerySet):
    def get_types(self, *args, **kwargs):
        all_queryset = self.all()
        return [b.get_a() for b in all_queryset]

# Our custom manager - we make sure we get CustomQuerySet, not QuerySet
class TypesManager(models.Manager):
    def get_queryset(self, *args, **kwargs):
        return CustomQuerySet(self.model)


class B(models.Model):
    # some fields

    # Managers
    objects = models.Manager()
    a_types_objects = TypesManager()

    # Get proper A "type"
    def get_a(self):
        if self.a_set.all() and self.a2_set.all():
            raise Exception('B object is related to A and A2 at the same time!')
        elif self.a_set.all():
            return A
        elif self.a2_set.all():
            return A2
        return None


class A(models.Model):
    b = models.ForeignKey(
        B
    )


class A2(models.Model):
    b = models.ForeignKey(
        B
    )
Run Code Online (Sandbox Code Playgroud)

现在你可以像这样使用它:

>>> from main.models import *
>>> B.a_types_objects.all()
<CustomQuerySet [<B: B object>, <B: B object>]>
>>> B.a_types_objects.all().get_types()
[<class 'main.models.A'>, <class 'main.models.A2'>]
>>> B.a_types_objects.filter(id=1)
<CustomQuerySet [<B: B object>]>
>>> B.a_types_objects.filter(id=1).get_types()
[<class 'main.models.A'>]
Run Code Online (Sandbox Code Playgroud)

使用a_types_objects方法与普通方法类似objects,但它返回 CustomQuerySet,它具有返回类列表的额外函数。

编辑:

如果您担心更改很多B.objects.(...)内容,B.a_types_objects.(...)您可以将主管理器设置为 TypesManager,如下所示:

class B(models.Model):
    # some fields

    # Override manager
    objects = TypesManager()
Run Code Online (Sandbox Code Playgroud)

其余代码将保持不变,但从现在开始,您将使用 CustomQuerySet 而不是 QuerySet - 仍然没有任何真正的变化。