日期便利(验证,显示等)部分日期在Django [英] Date Conveniences (Validation, Display, etc) for Partial Dates in Django

查看:58
本文介绍了日期便利(验证,显示等)部分日期在Django的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图在数据库中存储经常缺少月份和日期的日期。我目前的做法(似乎有很多不同的方法)是为这个使用三个字段:

  dob_year 
dob_month
dob_day

我想获得 DateFields 我可以。现在我可以想到的最重要的一个是验证。有效:

  2010 
2010,02
2010,02,28

还有一个问题,即将int转换为模板中的人类可读形式。可以说:

 < p> {{my_date | date:%Y}}< / p> 

但是,我必须做一些非常奇怪的事情,因为我需要它来支持部分日期和常规日期。我想我可以使用 @property 方法来完成此任务,但是我还没有将其排除在外。



我确定还有其他的放弃方式(如管理员中的日期小部件)。这里的想法也是受欢迎的,因为我知道部分日期是一个常见问题,但我主要关心的是现在的验证。



更新 :Twitter上的一位朋友指出,使用三个字段可以创建可怕的日期查询。不要使用三个字段进行部分日期,除非您想要考虑如何处理2011年7月至2012年6月之间的查询。

解决方案

将数据库中的日期作为文本存储是不好的做法。它不是可移植的,不是django查询api友好,而不是索引友好。



您可以将所有日期存储在数据库中,即使不是所有的日期都是必需的。例如, Oracle将日期和时间存储在日期即使你只需要日期。



然后你可以使用一个 DateField + ChoiceField 来存储偏置和相关的零件信息。例如:2015-02-01在月份截断。 2015-02-28完整的日期。 2015-01-01在年级截断。代码:

  class Item(models.Model):
PARTIAL_YEAR ='%Y'
PARTIAL_MONTH = '%Y-%m'
PARTIAL_DAY ='%Y-%m-%d'
PARTIAL_CHOICES =(
(PARTIAL_YEAR,'Year'),
(PARTIAL_MONTH,月'),
(PARTIAL_DAY,'Day'),

partial_date_date = models.DateField()
partial_date_part = models.CharField('Date part',
choice = PARTIAL_CHOICES,
max_length = 10,)

验证两个字段将由每个自己的小部件验证。您可以添加一个表单(清理和验证依赖于彼此的字段)或 model clean 验证级别。



查询使用 Q对象

  q_is_year = q(partial_date_part = Item.PARTIAL_YEAR)
q_by_year = q(partial_date_date__year = 2015)

q_is_month = q(partial_date_part = Item.PARTIAL_MONTH)
q_by_month = q(partial_date_date__year = 2105)
q_by_month& = q(partial_date_date__month = 2)

qs = Item.objects.filter(q_is_year& q_b y_year | q_is_month& q_by_month)

渲染显示为了在模板中呈现: / p>

 < p> {{item.partial_date_date | date:item.partial_date_part}}< / p> 

渲染表单要渲染表单控件,您可以使用JavaScript更改UI和帮助用户输入数据:

 日期类型:(*)年份()月()日
日期:动态更改表单窗口]

您可以发送3个窗口小部件控件,以便一次只显示一个。更改无线电日期类型选择的可见性。我使用 MultiWidget



EDITED 2015年8月13日,所有示例代码:


model.py




  from django.db import models 
from datetime import date

类项目(models.Model):
PARTIAL_YEAR ='%Y'
PARTIAL_MONTH ='%Y-%m'
PARTIAL_DAY ='%Y-%m - %d'
PARTIAL_CHOICES =(
(PARTIAL_YEAR,'Year'),
(PARTIAL_MONTH,'Month'),
(PARTIAL_DAY,'Day'),

partial_date_part = models.CharField('Date part',
choices = PARTIAL_CHOICES,
max_length = 10,)
partial_date_date = models.DateField()
some_comment = models.CharField('Comment',max_length = 100,)

def save(self,* args,** kwargs):
如果self.partial_date_part == self.PARTIAL_YEAR:
self.partial_date_date = date(self.partial_date_date.year,1,1 )
elif self.partial_date_part == self.PARTIAL_MONTH:
self.partial_date_date = date(self.partial_date_date.year,
self.partial_date_date.month,1)
super(Item ,self).save(* args,** kwargs)




.py




  from django import forms 
from django.forms import widgets
from datetime import date

class DateSelectorWidget(widgets.MultiWidget):
def __init __(self,attrs = None):
days = [(d,d)for d在范围(1,32)]
个月= [(m,m)m范围(1,13)]
年= [(年,年)年(2011年,2012年, 2013)]
_widgets =(
widgets.Select(attrs = attrs,choices = days),
widgets.Select(attrs = attrs,choices = months),
widgets.Select(attrs = attrs,choices = years),

超级(DateSelectorWidget,self).__ init __(_ widgets,attrs)

def解压缩(self,value):
如果value:
return [value.day,value.month, value.year]
return [None,None,None]

def format_output(self,rendered_widgets):
return''.join(rendered_widgets)

def value_from_datadict(self,data,files,name):
datelist = [
widget.value_from_datadict(data,files,name +'_%s'%i)
for i,枚举(self.widgets)中的小部件]
D = date(
day = int(datelist [0]),month = int(datelist [1]),year = int(datelist [2]) ,

返回D

类ItemForm(forms.Form):
partial_date_part = forms.CharField(widget = forms.RadioSelect)
partial_date_date = DateSelectorWidget()




view.py




  from django.http import HttpResponseRedirect 
from django.views.generic import查看
从从django.forms.models导入项目
importformform_factory
from .forms import DateSelectorWidget
from django import forms
from django.forms import widgets

MyDatAppView(View):
form_class = modelform_factory(Item,
exclude = [],
widgets = {'partial_date_date':
DateSelectorWidget(),})
初始= {'some_comment':' - * - ',}
template_name ='form.html'

def get(self,request,* args,** kwargs):
form = self.form_class(initial = self.initial)
return render(request,self.template_name,{'形式':form})

def post(self,request,* args,** kwargs):
form = self.form_class(request.POST)
如果form。 is_valid():
m = form.save()
return HttpResponseRedirect('/')

return render(request,self.template_name,{'form':form})

您应该在模板上添加javascript,以便在所选零件更改时隐藏/显示日期零件字段。


I am trying to store dates in my database that often lack the month and day. My current approach (there seem to be many different ways of doing this) is to use three fields for this:

dob_year
dob_month
dob_day

I'd like to get as many of the benefits of DateFields that I can. The most important one I can think of now is validation. Valid:

2010
2010,02
2010,02,28

Invalid:

2010,02,30

There's also the problem of converting ints into a human readable form in the templates. It's great to be able to say:

<p>{{my_date|date:"%Y"}}</p>

But with this, I'll have to do something very strange because I'll need it to support partial dates and regular ones. I'm thinking I might be able to accomplish this with a @property method, but I haven't sorted this out yet either.

I'm sure there are other conveniences I'm giving up too (like date widgets in admin). Ideas here are welcome too since I know partial dates are a common issue, but I'm mostly concerned with validation at the moment.

Update: A friend on Twitter pointed out that using three fields for this creates horrible date queries. Do not use three fields for partial dates unless you want to think about how to handle queries like "between July of 2011 and June of 2012".

解决方案

Store dates in database as text is a bad practice. It is not portable, not django query api friendly, and not index friendly.

You can store all date in database even not all date is needed. For example, Oracle stores date and time in dates even you only need the date.

Then you can use a DateField + "ChoiceField" to store partialdate and relevant part information. Ex: 2015-02-01 truncate at month level. 2015-02-28 Full date. 2015-01-01 truncate at year level. Code:

class Item(models.Model):
    PARTIAL_YEAR='%Y'
    PARTIAL_MONTH='%Y-%m'
    PARTIAL_DAY='%Y-%m-%d'
    PARTIAL_CHOICES = (
      (PARTIAL_YEAR, 'Year'),
      (PARTIAL_MONTH, 'Month'),
      (PARTIAL_DAY, 'Day'),
    )
    partial_date_date = models.DateField()
    partial_date_part = models.CharField('Date part', 
                                          choices=PARTIAL_CHOICES,  
                                          max_length=10, )

Validate Both fields will be validated by each own widget. You can add a form clean (Cleaning and validating fields that depend on each other) or model clean validation level.

Quering Easy to make conditioned queries using Q objects:

q_is_year   = q( partial_date_part = Item.PARTIAL_YEAR )
q_by_year   = q( partial_date_date__year = 2015 )

q_is_month  = q( partial_date_part = Item.PARTIAL_MONTH )
q_by_month  = q( partial_date_date__year = 2105 ) 
q_by_month &= q( partial_date_date__month = 2 ) 

qs = Item.objects.filter( q_is_year&q_by_year | q_is_month&q_by_month )

Render display In order to render in template:

<p>{{item.partial_date_date|date:item.partial_date_part}}</p>

Render form To render form controls you can use JavaScript to change UI and help user with data entry:

  date type: (*) Year    ( ) Month     ( ) Day
  date:      [ change form widget dynamically  ]

You can send 3 widgets controls to form and show just one at a time. Change visibility on changing radio date type selection. I use MultiWidget.

EDITED 13 August 2015 with all sample code:

models.py

from django.db import models
from datetime import date

class Item(models.Model):
    PARTIAL_YEAR='%Y'
    PARTIAL_MONTH='%Y-%m'
    PARTIAL_DAY='%Y-%m-%d'
    PARTIAL_CHOICES = (
      (PARTIAL_YEAR, 'Year'),
      (PARTIAL_MONTH, 'Month'),
      (PARTIAL_DAY, 'Day'),
    )
    partial_date_part = models.CharField('Date part', 
                                          choices=PARTIAL_CHOICES,  
                                          max_length=10, )
    partial_date_date = models.DateField()
    some_comment = models.CharField('Comment', max_length=100, )

    def save(self, *args, **kwargs):
        if self.partial_date_part==self.PARTIAL_YEAR:
            self.partial_date_date = date( self.partial_date_date.year, 1, 1 )
        elif self.partial_date_part==self.PARTIAL_MONTH:
            self.partial_date_date = date( self.partial_date_date.year, 
                                          self.partial_date_date.month, 1 )  
        super(Item, self).save(*args, **kwargs)    

forms.py

from django import forms
from django.forms import widgets
from datetime import date

class DateSelectorWidget(widgets.MultiWidget):
    def __init__(self, attrs=None):
        days = [(d, d) for d in range(1,32)]
        months = [(m, m) for m in range(1,13)]
        years = [(year, year) for year in (2011, 2012, 2013)]
        _widgets = (
            widgets.Select(attrs=attrs, choices=days),
            widgets.Select(attrs=attrs, choices=months),
            widgets.Select(attrs=attrs, choices=years),
        )
        super(DateSelectorWidget, self).__init__(_widgets, attrs)

    def decompress(self, value):
        if value:
            return [value.day, value.month, value.year]
        return [None, None, None]

    def format_output(self, rendered_widgets):
        return ''.join(rendered_widgets)

    def value_from_datadict(self, data, files, name):
        datelist = [
            widget.value_from_datadict(data, files, name + '_%s' % i)
            for i, widget in enumerate(self.widgets)]
        D = date(
                day=int(datelist[0]),month=int(datelist[1]),year=int(datelist[2]),
            )
        return D

class ItemForm(forms.Form):
    partial_date_part = forms.CharField(widget=forms.RadioSelect)
    partial_date_date = DateSelectorWidget( )

view.py

from django.http import HttpResponseRedirect
from django.views.generic import View
from models import Item
from django.forms.models import modelform_factory
from .forms import DateSelectorWidget
from django import forms
from django.forms import widgets    

class MyDatAppView(View):
    form_class = modelform_factory(Item ,
                                   exclude=[], 
                                   widgets={ 'partial_date_date': 
                                              DateSelectorWidget() ,})
    initial = {'some_comment': '-*-', }
    template_name = 'form.html'

    def get(self, request, *args, **kwargs):
        form = self.form_class(initial=self.initial)
        return render(request, self.template_name, {'form': form})

    def post(self, request, *args, **kwargs):
        form = self.form_class(request.POST)
        if form.is_valid():
            m=form.save()
            return HttpResponseRedirect('/')

        return render(request, self.template_name, {'form': form})

You should add javascript on template to hide/show date part fields when selected part changes.

这篇关于日期便利(验证,显示等)部分日期在Django的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆