Django - 查询列表中的任何项目在多对多字段中的任何对象

Posted

技术标签:

【中文标题】Django - 查询列表中的任何项目在多对多字段中的任何对象【英文标题】:Django - Query for any objects where any item from list is in ManytoMany field 【发布时间】:2017-04-12 15:02:28 【问题描述】:

我在 Django 中有一个模型,它有一个名为“accepted_insurance”的多对多字段。我有一个表单,它使用包含保险提供商列表的查询字符串提交获取请求。我正在尝试编写一个查询,上面写着“如果查询字符串列表中的任何项目都在多对多字段列表中,则过滤这些对象。”。是否有 Django 查询快捷方式?我尝试使用“包含”,但我收到了一个类型错误,即相关字段的查找无效,我确信这只会说明列表是否包含列表。

models.py

class Provider(models.Model):
    title = models.CharField(max_length=255, null=True, blank=True)
    first_name = models.CharField(max_length=255, null=True, blank=True)
    middle_name = models.CharField(max_length=255, null=True, blank=True)
    last_name = models.CharField(max_length=255, null=True, blank=True)
    email = models.EmailField(null=True, blank=True)
    phone = models.CharField(max_length=40, null=True, blank=True)
    extension = models.CharField(max_length=10, null=True, blank=True)
    company = models.CharField(max_length=255, null=True, blank=True)
    age = models.IntegerField(null=True, blank=True)
    about = models.TextField(default='', null=True, blank=True)
    position = models.CharField(max_length=255, null=True, blank=True)

    cost_per_session = models.CharField(max_length=255, null=True, blank=True)
    accepts_insurance = models.BooleanField(default=False)
    accepted_insurance = models.ManyToManyField('Insurance', blank=True)
    payment_methods = models.ManyToManyField('PaymentMethod', blank=True)

request.GET

http://localhost:8004/directory/?search=timothy&insurance=cigna,aetna,optum_health,united_behavioral,blue_cross_blue_shield

<QueryDict: 'insurance': ['cigna,aetna,optum_health,united_behavioral,blue_cross_blue_shield'], 'search': ['timothy']>

views.py 查询

for param in request.GET:
    if param.lower() == 'insurance':
        all_providers = all_providers.filter(accepted_insurance__contains=param)

【问题讨论】:

【参考方案1】:

__in 是您需要的运算符。

但是,您还有其他一些问题。首先不需要遍历查询字典;它是一个dict,你可以通过key访问它。

其次,您目前只有一个字符串;您需要使用split(',') 方法将其拆分为字符串列表。

第三,您需要根据 Insurance 模型上的字段进行实际过滤 - 大概它有一个“名称”字段。

所以:

insurance = request.GET.get('insurance', '').split(',')
all_providers = all_providers.filter(accepted_insurance__name__in=insurance)

【讨论】:

那么如果接受的保险有两个标题为“Blue Cross Blue Shield”和“Cigna”的对象,它会尝试查看这两个标题是否都在保险字典中吗? 没有。它将匹配在其接受的保险字段列表中具有任何名称的任何提供者。 太棒了,谢谢丹尼尔!一些查询快捷方式一开始听起来有点反直觉,但如果它有效,它就可以工作。 请注意,如果提供者匹配列表中的多个项目,它可能会在输出中出现两次;将.distinct() 添加到查询中以防止这种情况发生。 __in case insensitive 吗?

以上是关于Django - 查询列表中的任何项目在多对多字段中的任何对象的主要内容,如果未能解决你的问题,请参考以下文章

Django如何过滤多对多字段中的对象,而不是原始查询集

Django查询多对多子集包含

Django 多对多字段过滤器列表

django - 如何查询仅描述的对象存在于多对多字段中的位置

JPQL在多对多关系上左外连接

完全加入多对多字段 Django