Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/django/20.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
或在django过滤器中使用关系时过滤器的定义_Django_Django Rest Framework_Django Filter_Django Filters - Fatal编程技术网

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

或在django过滤器中使用关系时过滤器的定义,django,django-rest-framework,django-filter,django-filters,Django,Django Rest Framework,Django Filter,Django Filters,我有三个模型,其简单关系如下: http://address/persons?start_time_0=2000-02-01&start_time_1=2000-03-01&billing_status=DE models.py views.py 我想从个人端点获取账单,该端点在账单中具有DE状态,并且在一段时间内: api/persons?start_time_0=2018-03-20&start_time_1=2018-03-23&billing_statu

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

http://address/persons?start_time_0=2000-02-01&start_time_1=2000-03-01&billing_status=DE
models.py views.py 我想从个人端点获取账单,该端点在账单中具有
DE
状态,并且在一段时间内:

api/persons?start_time_0=2018-03-20&start_time_1=2018-03-23&billing_status=DE
但结果并不是我想要的,它返回所有人在该期间都有一个会话,并且有一个状态为
DE
的账单,无论该账单是否在该期间

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

编辑 我试着写一个例子来说明我需要什么以及我从django过滤器中得到了什么。如果我在示例中使用下面的查询得到persons,我只得到两个人:

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';
编辑2 这是我在示例中的查询所依据的数据,使用这些数据,您可以看到我在上面提到的查询中必须返回的内容:

 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
编辑3 我尝试使用
prefetch\u related
连接表并获得预期的结果,因为我认为额外的连接会导致此问题,但这不起作用,我仍然得到相同的结果,并且没有任何效果

编辑4 这也有同样的问题。

我还没有解决方案;但我认为,在工作中,简明的问题总结会比我的头脑更聪明! 据我所知;您的核心问题是两个先决条件的结果:

  • 在相关模型上定义了两个离散过滤器;导致过滤器跨越多值关系
  • FilterSet
    实现过滤的方式
  • 让我们更详细地了解这些: 跨越多值关系的过滤器 这是更好地理解问题先决条件#1的重要资源:

    本质上,
    start\u time
    过滤器向查询集添加一个
    .filter(sessions\u start\u time=value)
    ,而
    billing\u status
    过滤器向过滤器添加一个
    .filter(sessions\u billing\u status=value)
    。这导致了上面描述的“跨越多值关系”问题,这意味着它将在这些过滤器之间执行
    ,而不是按照您的要求执行

    这让我想,为什么我们不在
    开始时间
    过滤器中看到同样的问题;但这里的诀窍是它被定义为一个
    DateFromToRangeFilter
    ;它在内部使用带有
    \uu range=
    结构的单个筛选器查询。如果它改为
    sessions\uuu start\u time\uu gt=
    sessions\uu start\u time\uu lt=
    ,我们这里也会遇到同样的问题

    FilterSet
    实现过滤的方式 谈话是廉价的;给我看看代码

    如您所见,
    qs
    属性通过迭代
    Filter
    对象列表来解析,将初始qs依次传递给每个对象并返回结果。请参见
    qs=filter\uu.filter(qs,value)

    这里的每个
    Filter
    对象定义了一个特定的
    def Filter
    操作,该操作基本上接受Queryset,然后向其添加一个连续的
    .Filter

    下面是一个来自
    BaseFilter
    类的示例

       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_方法(qs)(**{'%s_uu%s%%(self.name,lookup):value})

    因此,这两个先决条件为这个问题创造了完美的风暴。

    这对我来说很有效:

    类FooFilterSet(FilterSet):
    def过滤器查询集(自身,查询集):
    """
    重写基本methtod,以便使用多个`.filter()在queryset上进行迭代`
    调用,每个筛选器一个,它将累积查找表达式并在单个筛选器中应用它们
    `.filter()`调用-在多对多关系中使用显式“AND”进行筛选。
    """
    筛选器_kwargs={}
    对于名称,使用self.form.data.items()中的值:
    如果值不在空值中:
    查找=“%s\uuu%s%”(self.filters[name]。字段名称,self.filters[name]。查找表达式)
    filter_kwargs.update({lookup:value})
    queryset=queryset.filter(**过滤器)
    断言isinstance(queryset,models.queryset)\
    预期'%s.%s'返回查询集,但得到的是%s\
    %(类型(自身)。\uuuuu名称,名称,类型(查询集)。\uuuuu名称\uuuuuu)
    返回查询集
    

    重写
    filter\u queryset
    方法,使其累积表达式并在单个
    .filter()
    调用中应用它们

    在filters.py文件中而不是在views.py中对过滤器进行克隆。查看“设置”中的“已安装的应用程序”列表中是否有django筛选器。p
    Person
    如何与
    PersonSession
    计费模式相关?上面的代码看起来不完整。根据给定的信息,我可以得出的结论是,您的e正在将
    PersonSession
    计费
    (计费具有
    会话
    属性)和
    (假设
    分支会话
    反向映射与过滤器中使用的映射相关联)。尝试使用此人拥有的帐单进行筛选。类似的方法应该可以工作-
    start\u time=django\u filters.datefromtrangefilter(name='billings\u sessions\u\u start\u time',distinct=True)
    假设
    Person
    有一个属性
    billing
    。如果有帮助,请告诉我。对于模型中的问题,我很抱歉,我忘记了模型中的一些字段<代码>会话
    有一个指向
    人员的外键
    计费
    会话
    有一对一的关系。使用这些假设,我认为我的过滤器没有问题,必须按照我的预期工作,但事实并非如此。@GeancarloMurillo我不明白为什么更改过滤器实现所在的文件和位置会影响过滤器的结果?正如我所解释的,我从过滤器中得到了一些结果,但是
     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
    
    @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
    
       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