在 django 过滤器中使用关系时过滤器的 OR 定义

2023-12-11

我有三个模型,其简单关系如下:

模型.py

class Person(models.Model):
    first_name = models.CharField(max_length=20)
    last_name = models.CharField(max_length=20)

class PersonSession(models.Model):
    start_time = models.DateTimeField(auto_now_add=True)
    end_time = models.DateTimeField(null=True,
                                    blank=True)
    person = models.ForeignKey(Person, related_name='sessions')

class Billing(models.Model):
    DEBT = 'DE'
    BALANCED = 'BA'
    CREDIT = 'CR'

    session = models.OneToOneField(PersonSession,
                                   blank=False,
                                   null=False,
                                   related_name='billing')
    STATUS = ((BALANCED, 'Balanced'),
              (DEBT, 'Debt'),
              (CREDIT, 'Credit'))

    status = models.CharField(max_length=2,
                              choices=STATUS,
                              blank=False,
                              default=BALANCED
                              )

views.py

class PersonFilter(django_filters.FilterSet):
    start_time = django_filters.DateFromToRangeFilter(name='sessions__start_time',
                                 distinct=True)
    billing_status = django_filters.ChoiceFilter(name='sessions__billing__status',
                        choices=Billing.STATUS,
                        distinct=True)

    class Meta:
        model = Person
        fields = ('first_name', 'last_name')

class PersonList(generics.ListCreateAPIView):
    queryset = Person.objects.all()
    serializer_class = PersonSerializer
    filter_backends = (django_filters.rest_framework.DjangoFilterBackend)
    filter_class = PersonFilter

我想从个人端点获取账单DE计费状态和一段时间之间:

api/persons?start_time_0=2018-03-20&start_time_1=2018-03-23&billing_status=DE

但结果不是我想要的,这会返回所有人在该期间有一次会话,并且与DE状态,无论该账单是否在该期间内。

换句话说,似乎使用or我认为两个过滤器字段之间的操作这个帖子与此问题相关,但目前我找不到方法来获得我想要的结果。我正在使用 djang 1.10.3。

Edit

我尝试写一个example显示我需要什么以及我从 django 过滤器中得到什么。如果我在示例中得到使用以下查询的人,我只会得到两个人:

select * 
from 
test_filter_person join test_filter_personsession on test_filter_person.id=test_filter_personsession.person_id join test_filter_billing on test_filter_personsession.id=test_filter_billing.session_id 
where
start_time > '2000-02-01' and start_time < '2000-03-01' and status='DE';

这让我只得到第 1 个人和第 2 个人。但是,如果我从 url 中得到预期的类似内容,我会得到所有人的相似网址(至少有一个我期望相同的网址)如下:

http://address/persons?start_time_0=2000-02-01&start_time_1=2000-03-01&billing_status=DE

Edit2

这是我在示例中的查询所依据的数据,使用它们您可以看到我上面提到的查询中必须返回的内容:

 id | first_name | last_name | id |        start_time         |         end_time          | person_id | id | status | session_id 
----+------------+-----------+----+---------------------------+---------------------------+-----------+----+--------+------------
  0 | person     | 0         |  0 | 2000-01-01 16:32:00+03:30 | 2000-01-01 17:32:00+03:30 |         0 |  0 | DE     |          0
  0 | person     | 0         |  1 | 2000-02-01 16:32:00+03:30 | 2000-02-01 17:32:00+03:30 |         0 |  1 | BA     |          1
  0 | person     | 0         |  2 | 2000-03-01 16:32:00+03:30 | 2000-03-01 17:32:00+03:30 |         0 |  2 | DE     |          2
  1 | person     | 1         |  3 | 2000-01-01 16:32:00+03:30 | 2000-01-01 17:32:00+03:30 |         1 |  3 | BA     |          3
  1 | person     | 1         |  4 | 2000-02-01 16:32:00+03:30 | 2000-02-01 17:32:00+03:30 |         1 |  4 | DE     |          4
  1 | person     | 1         |  5 | 2000-03-01 16:32:00+03:30 | 2000-03-01 17:32:00+03:30 |         1 |  5 | DE     |          5
  2 | person     | 2         |  6 | 2000-01-01 16:32:00+03:30 | 2000-01-01 17:32:00+03:30 |         2 |  6 | DE     |          6
  2 | person     | 2         |  7 | 2000-02-01 16:32:00+03:30 | 2000-02-01 17:32:00+03:30 |         2 |  7 | DE     |          7
  2 | person     | 2         |  8 | 2000-03-01 16:32:00+03:30 | 2000-03-01 17:32:00+03:30 |         2 |  8 | BA     |          8

Edit3

我尝试使用prefetch_related连接表并获得我预期的结果,因为我认为额外的连接会导致这个问题,但这不起作用,我仍然得到相同的结果,并且没有任何影响。

Edit4

This issue有同样的问题。


我还没有解决办法;但我认为对问题的简洁总结会比我在工作中激发更多更好的思想!

据我了解;您的核心问题是两个先决条件的结果:

  1. 事实上,您在相关模型上定义了两个离散滤波器;导致过滤器跨越多值关系
  2. The way FilterSet实现过滤

让我们更详细地看看这些:

过滤器跨越多值关系

这是一个很好的资源,可以帮助您更好地理解问题先决条件#1:https://docs.djangoproject.com/en/2.0/topics/db/queries/#spanning-multi-valued-relationships

本质上,start_time过滤器添加了一个.filter(sessions__start_time=value)到你的查询集,以及billing_status过滤器添加了一个.filter(sessions_billing_status=value)到过滤器。这会导致上述“跨越多值关系”问题,这意味着它将产生OR在这些过滤器之间而不是AND正如你所要求的那样。

这让我开始思考,为什么我们在start_time筛选;但这里的技巧是它被定义为DateFromToRangeFilter;它在内部使用单个过滤器查询__range=构造。如果相反的话sessions__start_time__gt= and sessions__start_time__lt=,我们在这里也会遇到同样的问题。

The way FilterSet实现过滤

空谈是廉价的;显示代码

@property
def qs(self):
    if not hasattr(self, '_qs'):
        if not self.is_bound:
            self._qs = self.queryset.all()
            return self._qs

        if not self.form.is_valid():
            if self.strict == STRICTNESS.RAISE_VALIDATION_ERROR:
                raise forms.ValidationError(self.form.errors)
            elif self.strict == STRICTNESS.RETURN_NO_RESULTS:
                self._qs = self.queryset.none()
                return self._qs
            # else STRICTNESS.IGNORE...  ignoring

        # start with all the results and filter from there
        qs = self.queryset.all()
        for name, filter_ in six.iteritems(self.filters):
            value = self.form.cleaned_data.get(name)

            if value is not None:  # valid & clean data
                qs = filter_.filter(qs, value)

        self._qs = qs

    return self._qs

如您所见,qs属性是通过迭代列表来解决的Filter对象,将初始 q 依次传递给每个对象并返回结果。看qs = filter_.filter(qs, value)

Each Filter这里的对象定义了一个具体的def filter操作,基本上采用查询集,然后添加连续的.filter to it.

这是一个来自BaseFilter class

   def filter(self, qs, value):
        if isinstance(value, Lookup):
            lookup = six.text_type(value.lookup_type)
            value = value.value
        else:
            lookup = self.lookup_expr
        if value in EMPTY_VALUES:
            return qs
        if self.distinct:
            qs = qs.distinct()
        qs = self.get_method(qs)(**{'%s__%s' % (self.name, lookup): value})
        return qs

重要的代码行是:qs = self.get_method(qs)(**{'%s__%s' % (self.name, lookup): value})

所以这两个先决条件为这个问题创造了完美的风暴。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在 django 过滤器中使用关系时过滤器的 OR 定义 的相关文章

随机推荐

  • 如何防止 Spyne 包装我的回复?

    这是示例服务 NS my app namespace class MyMethodRS ComplexModel tns NS Version XmlAttribute Unicode class MyService ServiceBase
  • Django Haystack 和 Whoosh 搜索工作正常,但 SearchQuerySet 返回 0 个结果

    编辑 更多信息在帖子底部 原问题 我似乎遇到了与这个 未解决的 问题相同的问题 django haystack Whoosh SearchQuerySet all 始终无 我已经在我的 Django 项目上使用 Whoosh 设置了 Hay
  • 使用ffmpeg丢弃容器中的数据流

    我正在尝试使用 ffmpeg 删除 Mp4 容器内的数据 字幕 流 这是 ffprobe 的屏幕截图 Input 0 mov mp4 m4a 3gp 3g2 mj2 from test m4v Metadata major brand is
  • Ansible,如何在主机清单中定义列表?

    我有一个剧本 我想在我的主机文件中定义一个字符串列表 这是我的主机文件 dashboard 1 2 3 4 dashboard domain test site domain one two foo bar 这是我尝试使用以下方法编写的剧本
  • WCF 中的 Owin 中间件替代品是什么?

    我正在尝试在 WCF 应用程序中实现多租户 但面临一些问题 所以我已经在应用程序中配置了 Autofac 并且 Autofac 也支持多租户与WCF 现在我的情况略有不同 我有一个正在使用此 WCF 服务的移动应用程序 该服务部署在 Azu
  • Microsoft Office 365 组:来宾用户无法使用图形端点进行驱动器调用[关闭]

    Closed 这个问题是无法重现或由拼写错误引起 目前不接受答案 我们的应用程序通过对驱动器项执行 Get 调用来读取组驱动器内容 这对于内部成员和来宾用户来说过去都工作得很好 它现在适用于内部成员 但不再适用于来宾用户 以下是示例调用 h
  • 网页抓取协助

    我必须从这个网页中提取一些信息 我知道有更简单的方法来获取这些信息 但这就是我的任务 到目前为止 我一直在尝试这样做 import pandas as pd import requests from bs4 import Beautiful
  • 为什么这两个正则表达式的行为不一样?

    我正在尝试使用这样的构造函数语法创建正则表达式new RegExp bword b g 但它的行为并不符合预期 相反 它似乎创建了一个如下所示的正则表达式 bwor b g缺少最后一个字母 我必须使用构造函数语法来创建正则表达式 因为我是从
  • R data.table 如果另一列为 NA,则删除一列重复的行

    这是一个示例 data table dt lt data table col1 c A A B C C D col2 c NA dog cat jeep porsch NA col1 col2 1 A NA 2 A dog 3 B cat
  • Linq To Sql - SQL 默认约束问题

    我在数据库中有一个 USER 表 该表有一个 RegistrationDate 列 该列的默认约束为 GETDATE 使用 LINQ 时 我不为 RegistrationDate 列提供任何数据以将其设置为默认值 但 SQL Server
  • 并非所有代码路径都会返回值,for 循环

    这段代码将比较用户名 and 密码存储在文本文件中 我认为这是因为 for 循环 它可能很简单 但我看不到它 public int loginCheck string users File ReadLines Username Passwo
  • 如何将 Crashlytics 与 iMessage 扩展一起使用?

    我的 iOS 应用程序中有一个 iMessage 扩展 Crashlytics 能否捕获其崩溃情况 我尝试添加相同的Fabric来自我的主应用程序的条目Info plist进入我的 iMessage 扩展程序Info plist 并将以下内
  • Libsvm 中的决策值

    我是 SVM 新手 我使用 Libsvm for Matlab 在预测阶段之后我得到了一个决策值数组 根据 SVM 理论 每个测试记录 z 被指定为正 如果 f z 1 其中 f z 定义为 f z 符号 w z b 那么如何将实例 z 的
  • 在 JBoss 中替换 Websphere 的 WorkManager?

    我们正在从 Websphere 迁移到 JBoss 但某些代码依赖于 Websphere 的 WorkManager com ibm websphere asyncbeans WorkManager 有没有人以前处理过这个问题 并对如何替换
  • 具有两个 Y 轴的图:置信区间

    我试图用误差线和两个 y 轴绘制几个点 然而 在每次调用plotCI 或errbar 函数时 都会初始化一个新的绘图 无论是否有par new TRUE 调用 require plotrix x lt 1 10 y1 lt x rnorm
  • CustomControl DependencyProperty 绑定无法正常工作

    我写了一个自定义控件 它是一个带有按钮的文本框 可打开 OpenFileDialog TextBox 的 Text 属性绑定到我的依赖属性 FileName 如果用户通过 OpenFileDialog 选择文件 我会将结果设置为此属性 Te
  • 使用 sympy 展开索引符号方程

    下面我有一个使用索引符号编写的方程 这个方程可以用图中的六个方程来表示 第一个方程使用索引符号 爱因斯坦符号 https en wikipedia org wiki Einstein notation 在 U k k 中 逗号是导数的约定
  • PyTorch:addmm函数的用途

    以下 PyTorch 函数的目的是什么 doc torch addmm beta 1 mat alpha 1 mat1 mat2 out None 更具体地说 是否有任何理由更喜欢这个函数而不是仅仅使用 beta mat alpha mat
  • 在 ASP.Net 中创建 Repeater 控件

    我正在使用两个下拉菜单并将值绑定到该下拉菜单 现在添加一个新按钮 add new 当我单击 添加 按钮并保留之前选择的值时 我想在下面创建上述下拉列表 请帮助我做到这一点 您可以使用 ASP Net 的 Repeater 控件来达到所需的结
  • 在 django 过滤器中使用关系时过滤器的 OR 定义

    我有三个模型 其简单关系如下 模型 py class Person models Model first name models CharField max length 20 last name models CharField max