Django通过一个选择器函数获取FK

Django get FK through a selector function

我有 3 个模型:

class A:
start_date=DateField
end_date=DateField
... 
@property
def is_valid():
    if self.start_date is not None and self.end_date is not None:
            return self.start_date <= get_now().date() <= self.end_date
    elif (self.start_date is None or self.start_date <= get_now.date()) and self.end_date is None:
            return True

class B:
a = ManyToMany(A)

class C:
b = ForeignKey(B)

和一个选择器函数 get_valid_a's returns 给定单个 class B

class A 的所有有效实例

选择器函数:

def get_valid_a's(B):
    return B.A.filter((
            Q(start_date__lte=get_now().date()) &  
    Q(end_date__gte=get_now().date())) | (
            Q(start_date__lte=get_now().date()) & 
    Q(end_date__isnull=True)) | (
            Q(start_date__isnull=True) & Q(end_date__isnull=True))
        )

我正在寻找这样的东西:

C_with_valid_A = C.objects.filter(
    d_pk=d_pk, 
    b__a__isnull=False,
   <here I am lookig to do something like: b__a__in=get_valid_a's(b=b)
)

如有任何帮助,我们将不胜感激!

我会向 A 添加一个 custom manager 并向该管理器添加一个方法,该方法按有效结果进行过滤。你总是可以把它作为一个快速获胜的类方法

(我刚刚粘贴了查询,因为 verify/parse 几乎不可能:D)

class A:
    @classmethod
    def get_valid(cls):
        return cls.objects.filter((
            Q(start_date__lte=get_now().date()) & Q(end_date__gte=get_now().date())) | (
        Q(start_date__lte=get_now().date()) & 
Q(end_date__isnull=True)) | (
        Q(start_date__isnull=True) & Q(end_date__isnull=True)))

然后您可以在其他查​​询中使用此方法

C_with_valid_A = C.objects.filter(
    d_pk=d_pk,
    b__a__in=A.get_valid()
)

我阅读了一些 Django 文档并发现了一个非常有用的数据库级函数,可以在这种情况下使用 - Exists

抓取查询如下所示

C_with_valid_A = C.objects.annotate(
    has_valid_As=Exists(
    A.objects.filter((
            Q(start_date__lte=get_now().date()) &  
    Q(end_date__gte=get_now().date())) | (
            Q(start_date__lte=get_now().date()) & 
    Q(end_date__isnull=True)) | (
            Q(start_date__isnull=True) & Q(end_date__isnull=True)), 
    Bs=OuterRef('b')
    )).filter(has_valid_As=True,d=d_pk)

对于 Django >= 3.0,相同的查询可以写成

C_with_valid_A = C.objects.filter(
    Exists(
    A.objects.filter((
            Q(start_date__lte=get_now().date()) &  
    Q(end_date__gte=get_now().date())) | (
            Q(start_date__lte=get_now().date()) & 
    Q(end_date__isnull=True)) | (
            Q(start_date__isnull=True) & Q(end_date__isnull=True)), 
    Bs=OuterRef('b'),
    d=d_pk
))

这基本上与下面的第一个查询相同。在我的理解中,OuterRef表示模型C与模型B之间的关系。