views:

37

answers:

2

I am storing dates as an integer field in the format YYYYMMDD, where month or day is optional.

I have the following function for formatting the number:

def flexibledateformat(value):
    import datetime, re
    try:
        value = str(int(value))
    except:
        return None
    match = re.match(r'(\d{4})(\d\d)(\d\d)$',str(value))
    if match:
        year_val, month_val, day_val = [int(v) for v in match.groups()]
    if day_val:
        return datetime.datetime.strftime(datetime.date(year_val,month_val,day_val),'%b %e, %Y')
    elif month_val:
        return datetime.datetime.strftime(datetime.date(year_val,month_val,1),'%B %Y')
    else:
        return str(year_val)

Which results in the following outputs:

>>> flexibledateformat(20100415)
'Apr 15, 2010'
>>> flexibledateformat(20100400)
'April 2010'
>>> flexibledateformat(20100000)
'2010'

So I'm wondering if there's a function I can add under the model field class that would automatically call flexibledateformat.

So if there's a record r = DataRecord(name='foo',date=20100400) when processed in the form the value would be 20100400 but when output in a template using {{ r.date }} it shows up as "April 2010".

Further clarification

I do normally use datetime for storing date/time values. In this specific case, I need to record non-specific dates: "x happened in 2009", "y happened sometime in June 1996".

The easiest way to do this while still preserving most of the functionality of a date field, including sorting and filtering, is by using an integer in the format of yyyymmdd. That is why I am using an IntegerField instead of a DateTimeField.

This is what I would like to happen:

  1. I store what I call a "Flexible Date" in a FlexibleDateField as an integer with the format yyyymmdd.
  2. I render a form that includes a FlexibleDateField, and the value remains an integer so that functions necessary for validating it and rendering it in widgets work correctly.
  3. I call it in a template, as in {{ object.flexibledate }} and it is formatted according to the flexibledateformat rules: 20100416 -> April 16, 2010; 20100400 -> April 2010; 20100000 -> 2010. This also applies when I'm not calling it directly, such as when it's used as a header in admin (http://example.org/admin/app_name/model_name/).

I'm not aware if these specific things are possible.

Also

I have already written a template filter that can perform this function -- ({{object.flexibledate|flexibledateformat}}) -- but I'd rather not have to call the filter every time I want to output one of these values. Except when outputting the form, I pretty much never want to see the number.

+2  A: 

I think the most djangoish way of accomplishing a similar effect would be to define a custom method on a model:

class Model(models.Model):
    date = models.IntegerField()
    ...

    def flexibledate(self):
        return flexibledateformat(self.date)

You can use it in a template like this:

{{ r.flexibledate }}

I also wonder why are you using an IntegerField instead of a native DateTimeField.

Update: You can still use the custom method as an option for list_display in Django Admin. If you want the column header to say something else then simply the method's name use the "short_description" option, like this:

class Model(models.Model):
    date = models.IntegerField()
    ...

    def flexibledate(self):
        return flexibledateformat(self.date)
    flexibledate.short_description = 'Date'

and then you just use it the same way you would use an ordinary field:

class YourModelAdmin(admin.ModelAdmin):
    list_display = ('title', 'flexibledate')
admin.site.register(YourModel, YourModelAdmin)
Ludwik Trammer
"I also wonder why are you using an IntegerField instead of a native DateTimeField."Because as far as I understand, `2009-04-00` and `2009-00-00` are not valid values for a `DateTimeField`.In my models I'm not using models.IntegerField(), I'm using FlexibleDateField(), a custom model field. I'm well aware that I can add a function to the model, but what I'm hoping is there is a special function for model fields analagous to how `__unicode__` works: where I would output a value that is a `FlexibleDateField`, it would output the integer formatted using `flexibledateformat`.
Jordan Reiter
Well, you can play with getters and setters, but I think defining a method and being able to easily access both the "real" and the "flexible" value is a much cleaner solution (in oposite to blocking an access to the raw value). It is also consistent with how Django itself handles similar situations.
Ludwik Trammer
One area that I'd really like to get this working is in /admin/app_name/model_name/ where I am using these as columns in the list view. Basically, it needs to be able to sort by the value (in Integer form) and *then* output it using the flexibledateformat function. I'm not at all sure how this would work.
Jordan Reiter
Just put `ordering = ['date']` in model's meta class, and `'flexibledate'` in model's ModelAdmin list_display option (`list_display = ('title', 'flexibledate')`). Another reason to keep those two separate.
Ludwik Trammer
Oh, and you can specify the column's header doesn't necessary have to be a method's name. I updated my original post for more information.
Ludwik Trammer
A: 

That is not necesary, read about humanize and filtertag time

diegueus9
Unless I'm misreading the docs, these are for DateTime values.
Jordan Reiter