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

2024-09-28 01:23:59 发布

您现在位置:Python中文网/ 问答频道 /正文

我使用integerangefield(PostgreSQL的特定字段)来表示发出bancnote的年份。在

当向数据库添加对象并使用非空范围(如1990-2000)进行过滤时,工作正常,但是很少有bancnotes,它们只在一年内发布,因此期间为2005-2005。当这样设置范围时,在对象添加到db后,该值变为“None None”。在

似乎IntegerangeField不接受空范围。在

我试图用blank=True,null=True来设置“2005-(这里没有值)”这样的范围,这对我来说很好,但是在这种情况下过滤器不适用于这个对象。在

为了更清楚地看到下面的例子:

  • 2003-2008:正确显示和过滤
  • 2003-2003:显示为“无”,过滤错误
  • 2003-(no value)/(no value)-2003:dislayed as'2003 None'/'None-2003'(对我来说很满意),过滤器不起作用

我们也在考虑使用DateRangeField,但它同时提供了日期和月份作为输入,这会造成混乱。有没有其他可行的正确的方法?在

希望我对我的情况很清楚,期待任何建议。请随时询问,我会提供任何信息。提前谢谢!在

这是我的模型.py

from django.contrib.postgres.fields import IntegerRangeField
from django.core.validators import MinValueValidator, MaxValueValidator
from django.db import models
from datetime import datetime


class Bancnote(models.Model):
    Dollar= 'Dollar'
    Euro= 'Euro'

    TYPE_CHOICES = (
        (Dollar, 'Dollar'),
        (Euro, 'Euro')
    )

    type = models.CharField(max_length=11, choices=TYPE_CHOICES, default=Dollar)
    par = models.PositiveIntegerField()
    year = IntegerRangeField(null=True, blank=True)
    size = models.CharField(max_length=7)
    sign = models.CharField(max_length=20)
    desc = models.TextField(max_length=200)
    image = models.ImageField(upload_to='bons_images')

    def __str__(self):
        return str(self.par) + ' ' + self.type + ' ' + str(self.year.lower) + '-' + str(self.year.upper)

过滤器.py

^{pr2}$

视图.py

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)

索引.html

{% 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 %}

Tags: djangofromimportdividmodelstypeli
1条回答
网友
1楼 · 发布于 2024-09-28 01:23:59

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

All of the range fields translate to psycopg2 Range objects in python, but also accept tuples as input if no bounds information is necessary. The default is lower bound included, upper bound excluded; that is, [).

简而言之

  • tuple(2005, None)无效,因为postgres有效地将空边界视为无穷大。过滤依次失败,因为无穷大存在于边界检查之外。在
  • tuple(2005, 2005)无效,因为Django默认为排除的上限。Postgres将[2005,2005)规范化为空,因为有效的范围不存在。在
  • 另外,您的tuple(2003, 2008)范围不正确,因为2008年不包括在内。我很确定,如果你过滤了2008年到2010年的范围,它将被排除在外。在

要表示一年,可以使用以下任一方法:

  • tuple(2005, 2006)
  • Range(2005, 2005, bounds='[]')注意边界是一个字符串文本(psycopg2 docs)。在

关于过滤,过滤器执行startwsithendswith检查,我认为这是包含。因此,在2005年到2005年之前过滤您的年度应该会得到DB的预期值。一旦正确存储了范围,则过滤器应正常工作。在

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

示例范围:

from psycopg2.extras import NumericRange

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

相关问题 更多 >

    热门问题