2009-10-04 8 views
23

Mam model, w którym muszę przechowywać rok urodzenia. Używam administratora django. Osoba używająca tego będzie codziennie wypełniała mnóstwo ludzi, a funkcja DateField() pokazuje zbyt wiele (nie interesuje go dzień/miesiąc).Wyświetlany tylko rok w django admin, YearField zamiast DateField?

To makieta model pokazano, jak to jest teraz:

class Person(models.Model): 
    name = models.CharField(max_length=256) 
    born = models.IntegerField(default=lambda: date.today().year - 17) 

Jak widać, większość ludzi ma 17 lat, więc jestem coraz ich rok urodzenia jako domyślne.

Czy mogę to zrobić lepiej? Jak mogę wydobyć YearField z DateField? Jeśli robię YearField, mogę nawet zrobić kilka "łatwych tagów" takich jak "teraz", które ma ta data. (Oczywiście wyspecjalizowany BornYearField miałby łatwe przyciski na rok 1989, 1990, 1991 i inne wspólne lata)

Odpowiedz

9

Ponadto, i nie jest to istotne dla twojej sprawy, ale warto wiedzieć, nie używaj datetime.date.today() lub datetime.datetime.now() jako domyślne. Jest to wykonywane raz, gdy serwer jest uruchamiany.

Jesteś znacznie lepiej mijając callables w:

date = models.DateField(default=datetime.date.today) 

Uwaga, można użyć lambda aby względna:

date = models.DateField(default=lambda : datetime.date.today() - datetime.timedelta(days=6210)) 

Oczywiście, to jest naiwny i zakłada tam w ostatnich 17 latach było 5 lat przestępnych.

+0

Tak, znałem ten problem. Jednak myślałem, że ponieważ jest to rok tylko po to, aby pomóc ludziom w zakładaniu nowych członków przez cały dzień, potrzebuje tylko aktualizacji raz w roku. Po prostu musi "prawie trafić" w średnim wieku. Ale dziękuję, oczywiście rozwiązanie lambda jest lepsze. –

+9

Czy to tylko ja lub ta przecząca odpowiedź nie dotyczy pytania? –

6

Można też to zrobić:

YEARS = (
    ("1990", "1990"), 
    ("1991", "1991"), 
    ("1992", "1992"), 
    # P.e. generate a list from 1960 to date.today().year 
    # The reason why they choice key and text value are the 
    # same is that if you generate from 1960 to 2060 it will collide. 
    # 
    # E.g 
    # from datetime import datetime 
    # def tuplify(x): return (x,x) # str(x) if needed 
    # current_year = datetime.now().year 
    # YEARS = map(tuplify, range(1930, current_year + 1)) # range(1,4) gives [1,2,3] 
) 

class Whatever(models.Model): 
    # Show a list with years 
    birthdate = models.IntegerField(max_length=2, choices=YEARS) 

Mam nadzieję, że to pomoże.

+0

Django ignoruje 'max_length' dla' IntegerField' i ostrzeże Cię w Django 1.8+. Zobacz [this] (http://stackoverflow.com/questions/30849862/django-max-length-for-integerfield), aby uzyskać więcej informacji. – freethebees

+1

Twój pierwszy krotki YEARS powinien być liczbą całkowitą, ponieważ typem daty urodzenia jest IntegerField. Możesz użyć rozumienia listy tutaj, aby zbudować wybory i mieć dość proste stwierdzenie. –

21

znalazłem this solution który rozwiązuje całą sprawę dość elegancko myślę (nie mój kod):

import datetime 
YEAR_CHOICES = [] 
for r in range(1980, (datetime.datetime.now().year+1)): 
    YEAR_CHOICES.append((r,r)) 

year = models.IntegerField(_('year'), choices=YEAR_CHOICES, default=datetime.datetime.now().year) 

Edit początek zakres rozszerzyć listę :-)

+11

Można to wszystko w jednym wierszu: 'YEAR_CHOICES = [(r, r) dla r w zakresie (1984, datetime.date.today(). Rok + 1)]' – Bobort

+0

domyślny powinien prawdopodobnie wyglądać 'domyślnie = lambda: datetime.datetime.now().year "w przeciwnym razie zaktualizuje domyślną wartość tylko wtedy, gdy usługa zostanie ponownie uruchomiona. – askvictor

+1

Ponadto, jeśli chcesz migracje do pracy, to nie możesz użyć lambda, więc musisz zdefiniować prostą funkcję' def current_year():. ..' i użyj tego (bez nawiasów) zamiast 'default = current_year' – askvictor

2

rozwiązania niełączącego model wybory:

from django.core.validators import MinValueValidator, MaxValueValidator 

class Person(models.Model): 
    year = models.PositiveIntegerField(
      validators=[ 
       MinValueValidator(1900), 
       MaxValueValidator(datetime.now().year)], 
      help_text="Use the following format: <YYYY>") 

to będzie również utworzyć zastępczy w polu tekstowym z wartością help_text.