Python Django如何允许在IntegerRangeField中使用空范围

Python Django如何允许在IntegerRangeField中使用空范围,python,django,postgresql,django-filter,Python,Django,Postgresql,Django Filter,我使用IntegerRangeField(PostgreSQL的特定字段)来表示发行bancnote的年份 将对象添加到db并使用非空范围(如1990-2000)进行过滤时效果良好,但是只有很少的bancnotes是在一年内发布的,因此这段时间是2005-2005年。当这样设置范围时,对象添加到db后,该值变为“无” 似乎IntegerRangeField不接受空范围 我试着用blank=True,null=True来设置像“2005-(此处无值)”这样的范围,这对我来说很好,但在本例中,过滤器

我使用IntegerRangeField(PostgreSQL的特定字段)来表示发行bancnote的年份

将对象添加到db并使用非空范围(如1990-2000)进行过滤时效果良好,但是只有很少的bancnotes是在一年内发布的,因此这段时间是2005-2005年。当这样设置范围时,对象添加到db后,该值变为“无”

似乎IntegerRangeField不接受空范围

我试着用blank=True,null=True来设置像“2005-(此处无值)”这样的范围,这对我来说很好,但在本例中,过滤器不适用于此对象

要更清楚,请查看以下示例:

  • 2003-2008:正确显示和筛选
  • 2003-2003:显示为“无”,过滤错误
  • 2003年-(无值)/(无值)-2003年:显示为“2003无”/“无-2003”(对我来说令人满意),过滤器对此不起作用
我们也在考虑使用DateRangeField,但它同时提供了日和月作为输入,这会造成混乱。有没有其他可能和正确的方法来做到这一点

希望我清楚我的处境,期待任何建议。请随意询问,我会提供任何信息。提前谢谢

这是我的模特

过滤器.py

views.py

index.html

{%extends'目录/base.html%}
{%block title%}目录{%endblock%}
{%load widget_tweaks%}
{%块边栏%}
    • {filter.form.type%中的类型为%1}
    • {%endfor%}
  • {%render\u field filter.form.par\u gt id='from'%}{%render\u field filter.form.par\u lt id='to'%}
  • {%render_field filter.form.year maxlength='4%}
搜寻 {%endblock%} {%block content%} {#在这里过滤#} {filter.qs%中的bon的百分比} {%if-forloop.counter0 |可除数为:“4”%} {%endif%} {%endfor%} {%endblock%}
主要问题是没有正确存储范围。根据django postgres

在python中,所有范围字段都转换为,但如果不需要边界信息,也接受元组作为输入。默认为包含下限,不包含上限;也就是说,
[)

总之,

  • tuple(2005,None)
    无效,因为postgres有效地将空边界视为无穷大。过滤反过来会失败,因为无穷大存在于边界检查之外
  • tuple(20052005)
    无效,因为Django默认为排除的上限。Postgres将
    [20052005)
    标准化为空,因为范围实际上不存在
  • 此外,您的
    tuple(2003,2008)
    范围不正确,因为2008不包括在内。我很确定,如果您筛选的范围是2008到2010,它将被排除在外
要表示一年,您需要使用以下任一选项:

  • tuple(20052006)
  • Range(20052005,bounds='[]')
    注意,bounds是一个字符串文本()
在过滤方面,过滤器执行一个
startwsith
endswith
检查,我认为这是包括在内的。因此,在2005年到2005年对您的年份进行过滤应该会从数据库中产生预期值。一旦范围正确存储,过滤器应该正常工作

Postgres范围供参考。第8.17.5节包含关于边界行为和规范化的信息

示例范围:

from psycopg2.extras import NumericRange

NumericRange(2005, 2008, bounds='[]')

主要问题是没有正确存储范围。根据django postgres

在python中,所有范围字段都转换为,但如果不需要边界信息,也接受元组作为输入。默认值为包含下限,排除上限;即
[)

总之,

  • tuple(2005,None)
    无效,因为postgres有效地将空边界视为无穷大。过滤反过来会失败,因为无穷大存在于边界检查之外
  • tuple(20052005)
    无效,因为Django默认为排除的上限。Postgres将
    [20052005)
    标准化为空,因为范围实际上不存在
  • 此外,您的
    tuple(2003,2008)
    范围不正确,因为2008不包括在内。我很确定,如果您筛选的范围是2008到2010,它将被排除在外
要表示一年,您需要使用以下任一选项:

  • tuple(20052006)
  • Range(20052005,bounds='[]')
    注意,bounds是一个字符串文本()
在过滤方面,过滤器执行一个
startwsith
endswith
检查,我认为这是包括在内的。因此,在2005年到2005年对您的年份进行过滤应该会从数据库中产生预期值。一旦范围正确存储,过滤器应该正常工作

参考的Postgres范围
from django import forms
import django_filters

from .models import Bancnote


class BancnoteFilter(django_filters.FilterSet):
    type = django_filters.ChoiceFilter(name='type', choices=Bancnote.TYPE_CHOICES,
                                       widget=forms.RadioSelect(attrs={'class': 'radio'}), empty_label=None)
    par_gt = django_filters.NumberFilter(name='par', lookup_expr='gte', widget=forms.Select)
    par_lt = django_filters.NumberFilter(name='par', lookup_expr='lte', widget=forms.Select)
    year = django_filters.NumericRangeFilter(name='year', lookup_expr='contained_by')

    class Meta:
        model = Bancnote
        fields = ['type', 'par_gt', 'par_lt', 'year']
from django.shortcuts import render, render_to_response
from django.template import RequestContext
from django.shortcuts import render

from .models import Bancnote
from .filters import BancnoteFilter


def index(request):
    bons_list = Bancnote.objects.all().order_by('par')
    bons_filter = BancnoteFilter(request.GET, queryset=bons_list)


def image(request):
    bons = Bancnote()
    variables = RequestContext(request, {
        'bons': bons
    })
    return render_to_response('catalogue/bon_detail.html', variables)
{% extends 'catalogue/base.html' %}
{% block title %}Catalogue{% endblock %}

{% load widget_tweaks %}

{% block sidebar %}
    <form method="get">
        <div class="well bs-sidebar" id="style" style="background-color:#fff">
            <ul class="nav nav-pills nav-stacked">
                <li>
                    <a href="#" class="toggle-menu" onclick="showcontent('#money-type')">Bancnote type
                        <i class="fa fa-chevron-up"></i>
                    </a>
                </li>
                <div id="money-type">
                    <ul class="nav nav-pills nav-stacked">
                        {% for type in filter.form.type %}
                            <li><a href="#">
                                {{ type.tag }}
                                <label for="{{ type.id_for_label }}">{{ type.choice_label }}</label>
                            </a></li>
                        {% endfor %}
                    </ul>
                </div>
                <li>
                    <a href="#" class="toggle-menu" onclick="showcontent('#par')">Bancnote par
                        <i class="fa fa-chevron-up"></i>
                    </a>
                </li>
                <div id="par">
                    {% render_field filter.form.par_gt id='from' %}{% render_field filter.form.par_lt id='to' %}
                </div>
                <li><a href="#" class="toggle-menu" onclick="showcontent('#period')">Issue years
                    <i class="fa fa-chevron-up"></i></a></li>
                <div id="period">
                    <div class="range-input">
                        {% render_field filter.form.year maxlength='4' %}
                    </div>
                    <div class="range-slider">
                        <input value="1917" min="1917" max="2017" step="1" type="range">
                        <input value="2017" min="1917" max="2017" step="1" type="range">
                    </div>
                </div>
            </ul>
        <button type="submit" class="btn btn-primary" style="text-align: center; width: 100%">
            <span class="glyphicon glyphicon-search"></span> Search
        </button>
        </div>
    </form>
{% endblock %}

{% block content %}

        <div class="container-fluid">
            <div class="row">
{# filtering here #}
                {% for bon in filter.qs %}
                    {% if forloop.counter0|divisibleby:"4" %}
            </div>
                        <div class="row">
                    {% endif %}
                    <div class="col-sm-3 col-lg-3">
                        <div style="display: block; text-align: center; margin: 0 auto">
                            <a href="{{ bon.id }}">
                                <img src="{{ bon.image.url }}" style="width: 50%; height: 50%"/>
                                <h5>{{ bon.par }} {{ bon.type }} {{ bon.year.lower}}-{{ bon.year.upper }}</h5>
                            </a>
                        </div>
                    </div>
                {% endfor %}
                        </div>
        </div>

{% endblock %}
from psycopg2.extras import NumericRange

NumericRange(2005, 2008, bounds='[]')