webentwicklung-frage-antwort-db.com.de

Jahresfeld in Django

Ich möchte, dass meine Benutzer ihr Geburtsjahr eingeben. Ich möchte nicht, dass sie dasselbe in das Formular eingeben, sondern das Jahr aus den verfügbaren Optionen auswählen. Ich wusste, dass ich in meinem Modell so etwas tun kann, wenn ich statt des Jahres ein Datum benötige:

class MyModel(models.Model):

    birthday = models.DateField(null=True, blank=True)

Ich kann dies in Formularen tun, damit der Benutzer das Datum aus dem Datumsauswahlfeld auswählen kann.

    birthday = forms.fields.DateField(widget=forms.widgets.DateInput(attrs={'type': 'date'}))

Für das Jahr kann ich einen CharField/IntegerField mit choices verwenden, ähnlich wie in dieser SO Antwort. 

import datetime
YEAR_CHOICES = [(r,r) for r in range(1984, datetime.date.today().year+1)]

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

Das Problem ist jedoch, dass eine Änderung des laufenden Jahres von etwa 2018 auf 2019 die verfügbaren Optionen nicht ändert.

Können Sie helfen oder Tipps geben, um zu erreichen, was ich tun möchte?

4
Inquilabi

Mein erster Gedanke war, ein Callable zu schreiben, das die Auswahlmöglichkeiten zurückgibt, die für jede Anfrage ausgewertet werden.

import datetime

def year_choices():
    return [(r,r) for r in range(1984, datetime.date.today().year+1)]

def current_year():
    return datetime.date.today().year

class MyModel(models.Model):
    year = models.IntegerField(_('year'), choices=year_choices, default=current_year)

Dies funktioniert jedoch nicht, da Djangos Check-Framework die Verwendung von year_choices nicht als Standardwert zulässt. Selbst wenn Sie die Auswahlmöglichkeiten hacken könnten, die dynamisch generiert werden, hätte dies den Nachteil, dass Django jedes Jahr versucht, eine Migration zu erstellen, wenn sich die Auswahl ändert. 

Sie können dies vermeiden, indem Sie stattdessen die Auswahl auf Formularebene generieren. Sie können Validatoren im Modell verwenden, um ungültige Daten zu verhindern. Beachten Sie, dass MaxValueValidator in eine Funktion max_value_current_year eingeschlossen ist, um jedes Jahr eine neue Migration zu vermeiden.

from Django.core.validators import MaxValueValidator, MinValueValidator

def current_year():
    return datetime.date.today().year

def max_value_current_year(value):
    return MaxValueValidator(current_year())(value)    

class MyModel(models.Model):
    year = models.IntegerField(_('year'), validators=[MinValueValidator(1984), max_value_current_year)

import datetime

def year_choices():
    return [(r,r) for r in range(1984, datetime.date.today().year+1)]

class MyForm(forms.ModelForm):
    year = forms.TypedChoiceField(coerce=int, choices=year_choices, initial=current_year)
7
Alasdair

Sie können die Optionen (Jahre) in das Formular einfügen, indem Sie IntegerField min_value und max_value verwenden. Im Modell können Sie IntegerField ohne Auswahlmöglichkeiten verwenden.

Sie brauchen sich also keine Sorgen zu machen, wenn sich das Jahr ändert, da Sie nur die Optionen im Formular ändern.

Wenn Sie das Jahr automatisch ändern möchten, könnte dies Ihnen helfen: Django forms integerField setze max_value zur Laufzeit

2
klassmann

Für diejenigen, die keine langen Auswahlfelder bevorzugen, d. H. In einer @ Alasdair-Lösung, stellen Sie sich ein Auswahlfeld von 1984 bis 2019 vor, eine solche lange Auswahlliste. Wie wäre es mit einem Feld? Sie können das Jahr eingeben und haben immer noch eine Möglichkeit zum Inkrementieren oder Dekrementieren. Um dies zu lösen, verwenden Sie models.PositiveIntegerField mit MinValueValidator und MaxValueValidator (siehe unten):

 import datetime 
 aus Django.core.validators importiert MaxValueValidator, MinValueValidator 
 aus Django.db-Importmodellen 
 
 
 def current_year (): 
 Rückgabe datetime.date.today (). Jahr 
 
 
 def max_value_current_year (Wert): 
 Rückgabe MaxValueValidator (current_year () ) (Wert) 
 
 
 Klasse EmployeesTrainings (models.Model): 
 name = models.ForeignKey (employee, default = '', leer = True, null) = True, on_delete = models.CASCADE) 
 Training_name = models.TextField (max_length = 200, default = '', leer = False, null = False) 
 Training_year = models.PositiveIntegerField (
 default = current_year (), Prüfer = [MinValueValidator (1984), max_value_current_year]) 
 
 
0