I have a modelform that uses __init__
to get kwargs. When running tests, I get a keyerror: 'requests'
. For my unit test, I setup an existing user and existing object to test for duplicates per user. Here is the form and test:
class CourseForm(ModelForm):
""" Form used for both creating a new course or updating an existing course."""
class Meta:
model = Course
fields = ('course_name', 'grade_level',)
def __init__(self, *args, **kwargs):
self.request = kwargs.pop('request')
self.qc = Course.objects.filter(user=self.request.user)
super().__init__(*args, **kwargs)
def clean(self):
super(CourseForm, self).clean()
course_name = self.cleaned_data.get('course_name')
grade_level = self.cleaned_data.get('grade_level')
# check exising course_name per user
# exclude(pk=self.instance.pk) because when we update we don't have to consider the current name
if course_name and self.qc.exclude(pk=self.instance.pk).filter(course_name__iexact=course_name).exists():
raise ValidationError("A course with that name already exists.")
return self.cleaned_data
class CourseFormTests(TestCase):
@classmethod
def setUp(self):
self.user = CustomUser.objects.create_user(
username='tester',
email='[email protected]',
password='tester123',
is_teacher=True,
is_active=True,
)
self.user.save()
self.my_course = Course(user=self.user,
id='4d192045-07fa-477f-bac2-5a99fe2e7c04',
course_name="name",
grade_level="SEC")
self.my_course.save()
def test_CourseForm_valid(self):
form = CourseForm(self.user, data={
'user': self.user,
'id': '4d192045-07fa-477f-bac2-5a99fe2e7c04',
'course_name': "Science",
'grade_level': "SEC"
},)
self.assertTrue(form.is_valid())
def test_CourseForm_invalid_name_too_long(self):
form = CourseForm(self.user, data={
'user': self.user,
'id': '4d192045-07fa-477f-bac2-5a99fe2e7c05',
'course_name': "NameistoolongforthistobeOKNameistoolongforthistobeOK",
'grade_level': "SEC"
},)
self.assertFalse(form.is_valid())
def test_CourseForm_invalid_name_exists(self):
form = CourseForm(self.user, data={
'user': self.user,
'id': '4d192045-07fa-477f-bac2-5a99fe2e7c05',
'course_name': "name",
'grade_level': "SEC"
},)
self.assertFalse(form.is_valid())
Here is a view that calls this form:
def courses(request):
"""view for listing and creating a course"""
course_list = Course.objects.filter(
user=request.user).order_by('course_name')
context = {'course_list': course_list}
user = request.user
if request.method == 'POST':
details = CourseForm(request.POST, request=request)
if details.is_valid():
if user.username != "Demo":
course = details.save(commit=False)
course.user = user
course.save()
form = CourseForm(request=request)
context['form'] = form
return render(request, "gradebook/courses.html", context)
else:
context['form'] = details
return render(request, "gradebook/courses.html", context)
else:
form = CourseForm(request=request)
context['form'] = form
return render(request, "gradebook/courses.html", context)
urls.py
path('courses/', views.courses, name='courses'),
The exact error is:
line 107, in __init__
self.request = kwargs.pop('request')
KeyError: 'request'
The form works in practice, but obviously doesn't pass the unit test.
Because your form requires the request in order to initialise, you can't just create an instance of it, you need to actually post your data as a request. You can do this with self.client.post,
eg
def test_CourseForm_invalid_name_exists(self):
# we use client.post because the form requires a request in __init__()
# if you need a logged in user, first use
# self.client.login(username='john', password='johnpassword')
response = self.client.post("/form/url/", data={
'user': self.user,
'id': '4d192045-07fa-477f-bac2-5a99fe2e7c05',
'course_name': "name",
'grade_level': "SEC"
},)
self.assertContains(response, "A course with that name already exists.", html=True)