gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-11-29 12:42:20 24 4
gpt4 key购买 nike

我正在使用 IntegerRangeField(PostgreSQL 的特定字段)来表示发行钞票的年份。

将对象添加到数据库并使用非空范围(例如 1990-2000)进行过滤时效果很好,但是只有很少的钞票,它们仅在一年内发行,因此时间段为 2005-2005。像这样设置范围时,对象添加到数据库后,该值变为'None-None'。

似乎 IntegerRangeField 不接受空范围。

我试图将范围设置为“2005-(此处无值)”,其中 blank=True,null=True,这对我来说很好,但在这种情况下过滤器不适用于此对象。

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

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

也想过用DateRangeField,但是输入的时候同时提供日和月,搞得一团糟。有没有其他可能和正确的方法来做到这一点?

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

这是我的models.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)

filters.py

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']

views.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)

index.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 %}

最佳答案

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

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 年的范围进行过滤,它将被排除在外。

要表示一年,您可以使用:

  • 元组(2005, 2006)
  • Range(2005, 2005, bounds='[]') 请注意,bounds 是一个字符串文字 ( psycopg2 docs )。

关于过滤,过滤器执行startwsithendswith 检查,我认为这是包容性。因此,从 2005 年到 2005 年过滤您的年份应该会从数据库中产生预期值。正确存储范围后,过滤器应该正常运行。

Postgres 范围 docs以供引用。第 8.17.5 节包含有关边界行为和规范化的信息。

示例范围:

from psycopg2.extras import NumericRange

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

关于python - Django 如何允许在 IntegerRangeField 中使用空范围,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43747720/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com