As in the title described I've got a form which validates correctly when I am using the FormView
. However as I started writting tests today
the same input fails in the TestCase and I get the following error:
{'programming_language': ['Select a valid choice. That choice is not one of the available choices.']}
These are the models, forms, views and the test I am using
# models.py
from django.db import models
class Tag(models.Model):
name = models.CharField(max_length=40, unique=True)
class ProgrammingLanguage(models.Model):
name = models.CharField(max_length=40, unique=True)
class Snippet(models.Model):
title = models.CharField(max_length=40)
programming_language = models.ForeignKey(ProgrammingLanguage, on_delete=models.CASCADE)
creation_date = models.DateTimeField(auto_now_add=True)
explanation = models.TextField()
code = models.TextField()
tags = models.ManyToManyField(Tag)
# forms.py
from django import forms
from django.utils.translation import gettext_lazy as _
from .models import Snippet
class SnippetForm(forms.ModelForm):
class Meta:
model = Snippet
exclude = ["creation_date"]
# views.py
from django.urls import reverse_lazy
from django.views import generic
from .models import Snippet
from .forms import SnippetForm
class SnippetFormView(generic.FormView):
template_name = "snippets/snippet_form.html"
form_class = SnippetForm
success_url = reverse_lazy("snippets")
def form_valid(self, form):
# for testing purposes
print(form.cleaned_data)
form.save()
return super().form_valid(form)
# test_forms.py
from django.test import TestCase
from snippets.forms import SnippetForm
from snippets.models import ProgrammingLanguage, Tag, Snippet
class SnippetFormTestCase(TestCase):
@classmethod
def setUpTestData(cls):
ProgrammingLanguage.objects.create(name="Javascript")
Tag.objects.create(name="website")
def test_forms(self):
form = SnippetForm({
'title': 'Test snippet title',
'programming_language': ProgrammingLanguage.objects.get(pk=1),
'code': 'code here',
'explanation': 'explanation here',
'tags': Tag.objects.all()
})
# calling is valid to get cleaned_data and original data
form.is_valid()
print(form.data)
print(form.cleaned_data)
self.assertEqual(form.errors, {})
This is the cleaned_data
I get in the view:
{'title': 'Test snippet title', 'programming_language': <ProgrammingLanguage: Javascript>, 'explanation': 'explanation here', 'code': 'code here', 'tags': <QuerySet [<Tag: website>]>}
And this is the data and the cleaned_data I get during the test:
# data
{'title': 'Test snippet title', 'programming_language': <ProgrammingLanguage: Javascript>, 'code': 'code here', 'explanation': 'explanation here', 'tags': <QuerySet [<Tag: website>]>}
# cleaned_data
{'title': 'Test snippet title', 'explanation': 'explanation here', 'code': 'code here', 'tags': <QuerySet [<Tag: website>]>}
Why is the ProgrammingLanguage an invalid choice during the test, but valid while using the website?
Try this in your test:
form = SnippetForm({
'title': 'Test snippet title',
'programming_language': 1, #ProgrammingLanguage.objects.get(pk=1),
'code': 'code here',
'explanation': 'explanation here',
'tags': Tag.objects.all()
})
When using a form for a model that has a primary key as one of its fields, you bound the form to data using the pk value for such field, not the model instance.
This is what FormView
does under the hood. And that's why your test is failing while the view works ok.
also be sure you have a programming language which pk
is 1.