【问题标题】:Django M2M Filter QuerySet With Exact M2M Set具有精确 M2M 集的 Django M2M 过滤查询集
【发布时间】:2015-01-28 23:28:37
【问题描述】:

假设我有以下 3 个模型,其中 2 个模型与第 3 个模型具有 M2M 关系。

class FirstModel(models.Model):
    third_model = models.ManyToMany('ThirdModel')


class SecondModel(models.Model):
    third_model = models.ManyToMany('ThirdModel')


class ThirdModel(models.Model):
    pass

现在,进一步假设我有一个特定的SecondModel 对象和一个FirstModel QuerySet。我需要过滤QuerySet,以便生成的QuerySet 只包含与ThirdModel 设置的M2M 关系与SecondModel 对象的M2M 关系设置与@987654332 完全相同的FirstModel 对象@。

def some_filtering_method(first_model_qs, second_model):
    third_models_set = second_model.third_model_set.all()
    first_model_ids = list()
    for third_model in third_models_set:
        first_model_ids.append(
            [first_model.pk
             for first_model in third_model.first_model_set.all()])
    intersection_of_first_model_ids = get_intersection(first_model_ids)
    return first_model_qs.filter(pk__in=intersection_of_first_model_ids)

在 Django 中是否有更 Pythonic 的方式来执行此操作?我尝试了以下操作但没有成功(在查看原始查询后,很明显为什么它不起作用)。

import operator

from django.db.models import Q


def some_filtering_method(first_model_qs, second_model):
    return first_model_qs.filter(
        reduce(
            operator.and_, 
            (Q(third_model_set__contains=x) 
             for x in second_model.third_model_set.all())
        )
    )

【问题讨论】:

    标签: django many-to-many


    【解决方案1】:

    我不确定最 Pythonic 的方式,但可能最 Djangonic 的方式是使用 custom Manager

    在 Django 1.6 及之前的版本中,需要分别设置 Manager 和 QuerySet:

    class SharedM2MSetQuerySet(models.QuerySet):
        def shared(self):
            pass
            # your code here
    
    class SharedM2MSetManager(models.Manager):
        def get_queryset(self):
            return PersonQuerySet(self.model, using=self._db)
    
        def shared(self,other):
            return self.get_queryset().shared(other)
    
        class FirstModel(models.Model):
            third_model = models.ManyToMany('ThirdModel')
            manager = SharedM2MSetQuerySet.as_manager()
    

    如果您使用的是 Django 1.7,您可以使用 QuerySet as a Manager 来快捷方式,如下所示:

    class SharedM2MSetQuerySet(models.Manager):
        def shared(self,other):
            pass
            # your code here
    
    class FirstModel(models.Model):
        third_model = models.ManyToMany('ThirdModel')
        manager = SharedM2MSetQuerySet.as_manager()
    
    class SecondModel(models.Model):
        third_model = models.ManyToMany('ThirdModel')
    
    class ThirdModel(models.Model):
        pass
    

    在这两种情况下,这都允许您执行以下操作:

    my_obj = SecondModel.objects.first()
    for i in FirstModel.objects.shared(my_obj):
        do_the_thing(i)
    

    【讨论】:

    • 只是为了澄清当您说“您的代码在这里”时,您指的是哪个代码?我的问题中的some_filtering_method 代码还是一些需要确定的自定义代码?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-06-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-13
    • 2020-11-24
    • 2014-02-11
    相关资源
    最近更新 更多