6

So. The following isn't very 'smart' ;)

MONTHS = (
    ('Jan', 'Jan'),
    ('Feb', 'Feb'),
    ('Mar', 'Mar'),
    ('Apr', 'Apr'),
    ('May', 'May'),
    ('Jun', 'Jun'),
    ('Jul', 'Jul'),
    ('Aug', 'Aug'),
    ('Sep', 'Sep'),
    ('Oct', 'Oct'),
    ('Nov', 'Nov'),
    ('Dec', 'Dec'),
)

YEARS = (
    ('1995', '1995'),
    ('1996', '1996'),
    ('1997', '1997'),
    ('1998', '1998'),
    ('1999', '1999'),
    ('2000', '2000'),
    ('2001', '2001'),
    ('2002', '2002'),
    ('2003', '2003'),
    ('2004', '2004'),
    ('2005', '2005'),
    ('2006', '2006'),
    ('2007', '2007'),
    ('2008', '2008'),
    ('2009', '2009'),
    ('2010', '2010'),
)

I'm newer to python, and would love to produce stuff like this 'pythonically'.

Such as,

  • a list of year tuples from 1995 to current year.
  • a list of the abbreviated months of the year

Thanks Stackers'

Daryl
  • 1,469
  • 5
  • 18
  • 30
  • Perhaps the question is how to produce lists like this, with 'for loops' I suppose. – Daryl Sep 28 '10 at 05:21
  • Btw. why are you using tuples consisting of two identical values? – ecik Sep 28 '10 at 09:51
  • 3
    @ecik: That's how django's choices works in forms/models. See http://www.djangoproject.com/documentation/models/choices/. The first item in the tuple is the actual value, and the second is what gets displayed. – Sam Dolan Sep 28 '10 at 18:20

5 Answers5

16
In [17]: from datetime import datetime

In [18]: tuple((str(n), str(n)) for n in range(1995, datetime.now().year + 1))
Out[18]:
(('1995', '1995'),
 ('1996', '1996'),
 ('1997', '1997'),
 ('1998', '1998'),
 ('1999', '1999'),
 ('2000', '2000'),
 ('2001', '2001'),
 ('2002', '2002'),
 ('2003', '2003'),
 ('2004', '2004'),
 ('2005', '2005'),
 ('2006', '2006'),
 ('2007', '2007'),
 ('2008', '2008'),
 ('2009', '2009'),
 ('2010', '2010'))

In [19]: import calendar

In [20]: tuple((m, m) for m in calendar.month_abbr[1:])
Out[20]:
(('Jan', 'Jan'),
 ('Feb', 'Feb'),
 ('Mar', 'Mar'),
 ('Apr', 'Apr'),
 ('May', 'May'),
 ('Jun', 'Jun'),
 ('Jul', 'Jul'),
 ('Aug', 'Aug'),
 ('Sep', 'Sep'),
 ('Oct', 'Oct'),
 ('Nov', 'Nov'),
 ('Dec', 'Dec'))
ars
  • 120,335
  • 23
  • 147
  • 134
  • 1
    Calendar module also provides an attribute called month_abbr which is probably more suitable here. – ecik Sep 28 '10 at 09:55
  • To get the current year you should do `import datetime; datetime.datetime.now().year + 1` as the second arg of the range. – Sam Dolan Sep 28 '10 at 18:19
8

Try using zip() to make a list of two-tuples.

MONTHS = ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec')
somemonth = models.TextField(max_length=3, choices=zip(MONTHS,MONTHS))

choices will be set to [('Jan', 'Jan'), ('Feb', 'Feb'), ...].


In response to the comments on this answer, the "tuple" list comprehension version would be:

tuple((m, m) for m in MONTHS)

Versus the zip version:

tuple(zip(MONTHS, MONTHS))

But strictly speaking, Django doesn't need a tuple of choices, so:

zip(MONTHS, MONTHS)
Annika Backstrom
  • 13,937
  • 6
  • 46
  • 52
3

See module time.

>>> import time

For the months we can use strptime to turn a month number 1-12 into a struct_time, and then use strftime to pull the month name out.

>>> [time.strftime('%b', time.strptime(str(i), '%m')) for i in range(1, 13)]
['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']

The years are more straightforward, we just need to know the current year (plus one, due to the way range works).

>>> [str(i) for i in range(1995, time.localtime().tm_year + 1)]
['1995', '1996', '1997', '1998', '1999', '2000', '2001', '2002', '2003', '2004', '2005', '2006', '2007', '2008', '2009', '2010']

I added str(i) to have the years returned as strings since that's the way you wrote them. If integers are okay then you can drop the whole list comprehension and simply use range(...).

John Kugelman
  • 349,597
  • 67
  • 533
  • 578
1
import datetime
from django.db import models
from django.utils.dates import MONTHS


class MyCoolModel(models.Model):
    YEARS = YEARS = [(i,)*2 for i in range(1995, datetime.today().year + 1)]

    month = models.PositiveSmallIntegerField(choices=MONTHS.items())
    year = models.PositiveIntegerField(choices=YEARS)
Dr Manhattan
  • 13,537
  • 6
  • 45
  • 41
0

Although some of the other answers might be "smarter", I dislike the idea of using a loop to define a tuple. Perhaps the following is a more readable compromise :

MONTHS = (
    ('Jan',) * 2,
    ('Feb',) * 2,
    ('Mar',) * 2,
    ('Apr',) * 2,
    ('May',) * 2,
    ('Jun',) * 2,
    ('Jul',) * 2,
    ('Aug',) * 2,
    ('Sep',) * 2,
    ('Oct',) * 2,
    ('Nov',) * 2,
    ('Dec',) * 2,
)

YEARS = (
    ('1995',) * 2,
    ('1996',) * 2,
    ('1997',) * 2,
    ('1998',) * 2,
    ('1999',) * 2,
    ('2000',) * 2,
    ('2001',) * 2,
    ('2002',) * 2,
    ('2003',) * 2,
    ('2004',) * 2,
    ('2005',) * 2,
    ('2006',) * 2,
    ('2007',) * 2,
    ('2008',) * 2,
    ('2009',) * 2,
    ('2010',) * 2,
)
Belmin Fernandez
  • 8,307
  • 9
  • 51
  • 75