Django-如何过滤多个多对多关系层 [英] Django - how to filter though multiple manyTomany relationship layers

查看:49
本文介绍了Django-如何过滤多个多对多关系层的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请考虑以下设置:

class ModelA(models.Model):
    foreign = models.ForeignKey(ModelB, on_delete=models.CASCADE)
    children = models.ManyToManyField('self', related_name="parent", symmetrical=False, blank=True)

class ModelB(models.Model):
    caption = models.CharField(db_index=True, max_length=50, null=False, unique=True)
    children = models.ManyToManyField(ModelC, blank=True)

class ModelC(models.Model):
    ...lots of fields

现在,给定ModelA对象的pk,我想获取并过滤所有相关的ModelC对象.这是我想要有效实现的目标:

Now, given the pk of a ModelA Object, I want to get and filter all the related ModelC Objects. Here is what i'm trying to achieve efficiently:

modelC_objects = ModelA.objects.get(pk=modelA_id).children.foreign.children
    .filter(pk__lte=last_id)      
    .exclude(is_private=True)
    .order_by('-pk')[0:100]
    .prefetch_related("other")
)

显然那是行不通的.我目前正在做这样的丑陋事情:

Obviously that doesn't work. I am currently doing something ugly like this:

modelA_objects = ModelA.objects.get(pk=modelA_id).children
modelC_querysets = [modelA.foreign.children for modelA in modelA_objects]
if modelC_querysets:
    modelC_objects = modelC_querysets[0]
    modelC_querysets.pop(0)
    for x in modelC_querysets:                    
        modelC_objects = modelC_objects | x
filtered = (modelC_objects.filter(pk__lte=last_id)      
   .exclude(is_private=True)
   .order_by('-pk')[0:100]
   .prefetch_related("other")
)

我如何实现我的尝试?

推荐答案

您要获取 ModelC 对象,因此需要在 ModelC 上启动查询.但是,如果您在模型中命名反向关系也可以有所帮助,这样可以更容易地沿相反的方向进行遍历:

You want to get ModelC objects, so you need to start your query on ModelC. But it would also help if you name the reverse relationships in your models so that it's easier to traverse in the opposite direction:

class modelA:
    foreign = models.ForeignKey(ModelB, related_name='modelAs' on_delete=models.CASCADE)
    ...

class modelB:
    children = models.ManyToManyField(ModelC, related_name='parents')
    ...

modelA_qs = ModelA.objects.filter(Q(id=pk) | Q(parents__id=pk))
modelC_objects = ModelC.objects.filter(parents__modelAs__in=modelA_qs)

第一个 parents 指代 ModelC 对象的父代 ModelB 对象,然后 modelAs 获取每个对象的 ModelA 对象.您可能应该在末尾添加 distinct()子句,因为您很可能会得到重复的 modelC 对象.

The first parents refers to the ModelB objects that are parents to a ModelC object, then modelAs fetches the ModelA objects for each of them. You probably should add a distinct() clause at the end, because you'll very likely get duplicate modelC objects.

这篇关于Django-如何过滤多个多对多关系层的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆