Daryl
Daryl

Reputation: 1489

Smart Loop List Creation in Python for Django Choice fields

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,

Thanks Stackers'

Upvotes: 6

Views: 5366

Answers (5)

Dr Manhattan
Dr Manhattan

Reputation: 14037

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)

Upvotes: 1

user7675
user7675

Reputation:

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)

Upvotes: 8

ars
ars

Reputation: 123468

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

Upvotes: 16

Belmin Fernandez
Belmin Fernandez

Reputation: 8637

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,
)

Upvotes: 0

John Kugelman
John Kugelman

Reputation: 361546

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

Upvotes: 3

Related Questions