J'essaie d'écrire un test pour mon formulaire qui utilise un ModelChoiceField personnalisé :
from django.forms import ModelChoiceField
class CycleModelChoiceField(ModelChoiceField):
def label_from_instance(self, cycle):
return str(cycle.begin_date)
Ce que l'utilisateur sélectionne dans ce champ doit être transmis à deux autres champs (DateField et radio ChoiceField) en remplaçant la fonction clean()
méthode. C'est une logique compliquée que je dois tester.
Voici donc ce que j'ai essayé dans mon test jusqu'à présent :
self.client.login(username='user', password='1234')
response = self.client.get(reverse('my_form'), follow=True)
cyc = list(CycleDate.objects.all())[0]
form_data = {'type_of_input': '0', 'cycle': cyc,'usage_type': 'E',}
form = EnergyUsageForm(data=form_data, user=response.context['user'])
Mais le form.is_valid()
retourne false et form.errors
dit :
{'cycle': [u'Select a valid choice. That choice is not one of the available choices.']}
Il doit y avoir un problème dans la construction de mon formulaire. 'cycle': cyc
ne fonctionne clairement pas comme prévu. J'ai également essayé 'cycle': '0'
y 'cycle': '1'
.
Quelle est la manière correcte de construire un formulaire comme celui-ci ?
EDITAR: Je devrais expliquer quels sont les choix possibles. Il n'y a qu'un seul CycleDate dans la base de données et un seul choix. Après avoir exécuté les lignes de mon test dans le shell, j'ai tapé form.fields['cycle'].choices.choice(cyc)
qui renvoie (1, '2015-05-01')
. Ce qui est étrange, c'est que form.fields['cycle'].queryset
renvoie à []
. Peut-être le problème est-il lié à cela ?
EDIT2: Voici mon formulaire avec cette méthode de nettoyage compliquée (lisez : désordonnée et terrible et honteuse) :
class EnergyUsageForm(forms.Form):
# Override init so that we can pass the user as a parameter.
# Then put the cycle form inside init so that it can access the current user variable
def __init__(self, *args, **kwargs):
user = kwargs.pop('user', None)
super(EnergyUsageForm, self).__init__(*args, **kwargs)
# Get the last 12 cycle dates for the current user
td = datetime.date.today
cycle_dates = CycleDate.objects.filter(cycle_ref=Account.objects.get(holder__user=user).cycle,
begin_date__lte=td).order_by('begin_date')
self.fields['cycle'] = CycleModelChoiceField(queryset = cycle_dates,
required = False,
widget = forms.Select(attrs={"onChange":'changeCalendar()'}),
label = "Choose a billing cycle")
type_of_input = forms.ChoiceField(required=False,
widget=forms.Select(attrs={"onChange": "switchInput()"}),
choices=INPUT,
initial='0',
label="Choose a way to display usage", )
end_date = forms.DateField(widget=forms.TextInput(attrs=
{
'class':'datepicker'
}),
label="Choose start date",
help_text='Choose a beginning date for displaying usage',
required=True,
initial=datetime.date.today,)
period = forms.ChoiceField(required=True,
widget=forms.RadioSelect,
choices=DISPLAY_PERIOD,
initial='01',
label="Choose period to display",)
usage_type = forms.ChoiceField(required=True,
widget=forms.RadioSelect,
choices=USAGE_TYPE,
initial='E',
label="Choose type of usage to display",)
def clean_end_date(self):
data = self.cleaned_data['end_date']
if datetime.date.today() < data:
raise forms.ValidationError("Don't choose a future date")
# Always return the cleaned data, whether you have changed it or
# not.
return data
def clean(self):
cleaned_data = super(EnergyUsageForm, self).clean()
selection = cleaned_data['type_of_input']
# Check if the user wants to use cycle_dates instead
if selection == '0':
# Set the end_date and period
cleaned_data['end_date'] = cleaned_data['cycle'].begin_date #MUST BE CHANGED TO END_DATE LATER
cleaned_data['period'] = cleaned_data['cycle'].duration
return cleaned_data
EDIT3 J'ai corrigé une coquille dans mon test, et voici aussi la méthode setUp de mon test :
client = Client()
def setUp(self):
user = User.objects.create_user(username = 'user', password = '1234')
user.save()
profile = UserProfile.objects.create(user = user)
profile.save()
account = Account(number=1, first_name='test',
last_name='User',
active=True,
holder=profile,
holder_verification_key=1)
account.save()
the_cycle = Cycle.objects.create(name = 'test cycle')
the_cycle.save()
cd = CycleDate.objects.create(begin_date = datetime.date(2015, 5, 1),
end_date = datetime.date.today(),
cycle_ref = the_cycle)
cd.save()
EDIT4 : En plus de tout ce désordre, je reçois maintenant KeyError: 'cycle'
chaque fois que j'appelle form.is_valid()
. Probablement dû au fait que la méthode clean() essaie d'accéder à cleaned_data['cycle'] lorsque le champ cycle a une sélection invalide.