web-dev-qa-db-fra.com

Champ Année à Django

Je veux que mes utilisateurs entrent leur année de naissance. Je ne veux pas qu'ils tapent la même chose dans le formulaire, mais plutôt l'année parmi les options disponibles. Je savais que je pouvais faire quelque chose comme ça dans mon modèle si j'avais besoin de sortir avec quelqu'un au lieu d'une année:

class MyModel(models.Model):

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

Je peux le faire dans des formulaires pour permettre à l'utilisateur de choisir la date à partir de datepicker.

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

Pour l'année, je peux utiliser un CharField/IntegerField avec choices semblable à ce qui a été fait dans ce SO réponse. 

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)

Le problème, cependant, est que le changement d’année en cours, passant de 2018 à 2019, ne changera pas les options disponibles.

Pouvez-vous aider ou fournir des astuces pour réaliser ce que je veux faire?

4
Inquilabi

Ma pensée initiale était d’écrire un appelable qui renvoie les choix, qui sera évalué pour chaque demande.

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)

Cependant, cela ne fonctionne pas, car la structure de contrôle de Django ne permet pas d'utiliser year_choices par défaut. Même si vous pouviez pirater les choix à générer de manière dynamique, cela aurait l'inconvénient que Django essaierait de créer une migration chaque année lorsque les choix changeraient. 

Vous pouvez éviter cela en générant les choix au niveau du formulaire. Vous pouvez utiliser des validateurs dans le modèle pour empêcher les données non valides. Notez que MaxValueValidator est encapsulé dans une fonction max_value_current_year pour éviter une nouvelle migration chaque année.

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

Vous pouvez mettre les options (années) dans le formulaire à l'aide de IntegerField min_value et max_value . Dans le modèle, vous pouvez utiliser le IntegerField sans choix.

Ainsi, vous ne vous inquiétez pas du changement d’année, car vous ne modifierez que les options du formulaire.

Si vous souhaitez modifier automatiquement l'année, cela pourrait vous aider: Django forms integerField set max_value on runtime

2
klassmann

Pour ceux qui ne préfèrent pas avoir des champs de choix longs, c'est-à-dire dans la solution @Alasdair, imaginez avoir un champ de choix de 1984 à 2019, une liste de choix aussi longue. Que diriez-vous d'avoir un champ, vous pouvez taper l'année et toujours avoir un moyen d'incrémenter ou de diminuer. Pour résoudre ce problème, utilisez modèles.PositiveIntegerField avec MinValueValidator et MaxValueValidator comme indiqué ci-dessous:

 import datetime 
 à partir de Django.core.validators importer MaxValueValidator, MinValueValidator 
 à partir de modèles d'importation Django.db 
 
 
 def current_year (): 
 renvoie datetime.date.today (). année 
 
 
 def max_value_current_year (value): 
 return MaxValueValidator (current_year () ) (valeur) 
 
 
 class EmployeesTrainings (models.Model): 
 name = models.ForeignKey (employee, default = '', blank = True, null = True, on_delete = models.CASCADE) 
 Nom_entrainement = models.TextField (max_length = 200, default = '', blank = False, null = False) 
 Train_year = models.PositiveIntegerField (
 default = current_year (), validators = [MinValueValidator (1984), max_value_current_year]) 
 
 
0
Ngatia Frankline