django - Django REST 框架。APITestCase。如何修复'bad_value、referenced_table_name、referenced_column_name'
问题描述
我有以下型号:
class Student(models.Model):
first_name = models.CharField(verbose_name='student first name', max_length=64)
last_name = models.CharField(verbose_name='student last name', max_length=64)
email = models.EmailField()
class Meta:
db_table = 'student'
def __str__(self):
return self.first_name + ' ' + self.last_name
class Course(models.Model):
name = models.CharField(max_length=255)
description = models.TextField()
start_date = models.DateField(null=True, blank=True, default=None)
end_date = models.DateField(null=True, blank=True, default=None)
class Meta:
db_table = 'course'
def __str__(self):
return self.name
class CourseParticipant(models.Model):
course = models.ForeignKey(Course, related_name='courses', on_delete=models.CASCADE)
student = models.ForeignKey(Student, related_name='student_name', on_delete=models.CASCADE)
completed = models.BooleanField(null=False, default=False)
class Meta:
db_table = 'course_participant'
def __str__(self):
return self.course, self.student
网址:
app_name = 'student'
urlpatterns = [
path(
'student', StudentAPIView.as_view(),
name='list'
),
path(
'student/detail/<int:pk>/',
StudentAPIDetailView.as_view(),
name='detail'
),
path(
'student/assign_student_to_course',
StudentAPIAssignToCourse.as_view(),
name='assign_student_to_course'
),
path(
'student/assigned_to_course',
StudentAPIAssignedToTheCourseView.as_view(),
name='assigned_to_course_list'
),
path(
'student/assigned_to_course/detail/<int:pk>/',
StudentAPIUnassignedFromTheCourseView.as_view(),
name='unassigned_to_course_list'
),
path(
'student/report/<int:pk>/',
StudentAPIPerformanceReport.as_view(),
name='student_performance'
)
]
意见:
import csv
from django.http import HttpResponse
from rest_framework import mixins, generics
from course.models import (
CourseParticipant
)
from student.models import (
Student
)
from student.serializers import (
StudentSerializer, AssignStudentToCourseSerializer, StudentAssignedToTheCourseSerializer
)
class StudentAPIView(
mixins.CreateModelMixin,
generics.ListAPIView
):
serializer_class = StudentSerializer
def get_queryset(self):
queryset = Student.objects.all()
return queryset
def post(self, request, *args, **kwargs):
return self.create(request, *args, **kwargs)
class StudentAPIDetailView(
mixins.UpdateModelMixin,
mixins.DestroyModelMixin,
generics.RetrieveAPIView,
):
serializer_class = StudentSerializer
def get_queryset(self):
query_set = Student.objects.all()
return query_set
def put(self, request, *args, **kwargs):
return self.update(request, *args, **kwargs)
def patch(self, request, *args, **kwargs):
return self.update(request, *args, **kwargs)
def delete(self, request, *args, **kwargs):
return self.destroy(request, *args, **kwargs)
class StudentAPIAssignToCourse(
generics.CreateAPIView
):
serializer_class = AssignStudentToCourseSerializer
def get_queryset(self):
queryset = CourseParticipant.objects.all()
return queryset
def post(self, request, *args, **kwargs):
return self.create(request, *args, **kwargs)
class StudentAPIAssignedToTheCourseView(
generics.ListAPIView
):
serializer_class = StudentAssignedToTheCourseSerializer
def get_queryset(self):
queryset = CourseParticipant.objects.all()
return queryset
class StudentAPIUnassignedFromTheCourseView(
mixins.DestroyModelMixin,
generics.RetrieveAPIView,
):
serializer_class = StudentAssignedToTheCourseSerializer
def get_queryset(self):
queryset = CourseParticipant.objects.all()
return queryset
def delete(self, request, *args, **kwargs):
return self.destroy(request, *args, **kwargs)
class StudentAPIPerformanceReport(
generics.RetrieveAPIView,
):
def get(self, request, *args, **kwargs):
response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = 'attachment; filename="report.csv"'
writer = csv.writer(response)
for student in Student.objects.filter(pk=self.kwargs['pk']):
assigned_courses = CourseParticipant.objects.filter(student=student)
completed_courses = assigned_courses.filter(completed=True)
headings = (
"student full Name",
"number of assigned courses to student",
"number of completed courses by student"
)
rows = (
student.full_name,
assigned_courses.count(),
completed_courses.count()
)
writer.writerow(headings)
writer.writerow(rows)
return response
并对其进行测试:
from rest_framework import status
from rest_framework.test import APITestCase
from rest_framework.reverse import reverse as api_reverse
from course.models import CourseParticipant
from .models import Student
class StudentAPITestCase(APITestCase):
def setUp(self):
student_obj = Student.objects.create(
first_name='test',
last_name='student',
email='test_student@gmail.com',
)
def create_item(self):
url = api_reverse('student:list')
data = {
'first_name': 'some_first_name_for_test',
'last_name': 'some_last_name_for_test',
'email': 'test_student@gmail.com'
}
response = self.client.post(url, data, format='json')
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
self.assertEqual(Student.objects.count(), 2)
return response.data
def test_student_create(self):
data = self.create_item()
data_id = data.get('id')
rud_url = api_reverse('student:detail', kwargs={'pk': data_id})
rud_data = {
'first_name': 'some_new_first_name_for_test',
'last_name': 'some_new_last_name_for_test'
}
get_response = self.client.get(rud_url, rud_data, format='json')
self.assertEqual(get_response.status_code, status.HTTP_200_OK)
def test_student_update(self):
data = self.create_item()
data_id = data.get('id')
rud_url = api_reverse('student:detail', kwargs={'pk': data_id})
rud_data = {
'first_name': 'some_new_first_name_for_test',
'last_name': 'some_new_last_name_for_test',
'email': 'test_student@gmail.com'
}
put_response = self.client.put(rud_url, rud_data, format='json')
self.assertEqual(put_response.status_code, status.HTTP_200_OK)
def test_student_delete(self):
data = self.create_item()
data_id = data.get('id')
rud_url = api_reverse('student:detail', kwargs={'pk': data_id})
delete_response = self.client.delete(rud_url, data_id, format='json')
self.assertEqual(delete_response.status_code, status.HTTP_204_NO_CONTENT)
get_response = self.client.delete(rud_url, format='json')
self.assertEqual(get_response.status_code, status.HTTP_404_NOT_FOUND)
class StudentAssignToCourseAPITestCase(APITestCase):
def setUp(self):
student_obj = CourseParticipant.objects.create(
course_id=1,
student_id=1,
)
def test_create_item(self):
url = api_reverse('student:assign_student_to_course')
data = {
'course_id': 1,
'student_id': 1,
}
response = self.client.post(url, data, format='json')
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
self.assertEqual(Student.objects.count(), 2)
return response.data
StudentAPITestCase 的所有测试均已通过,但 StudentAssignToCourseAPITestCase 的测试失败并带有一些 Traceback:
回溯(最近一次通话最后一次):文件“/home/leonidsoputnyak/Документы/project/test_task/venv/lib/python3.7/site-packages/django/test/testcases.py”,第 274 行,通话中 self._post_teardown() 文件“/home/leonidsoputnyak/Документы/project/test_task/venv/lib/python3.7/site-packages/django/test/testcases.py”,第 1009 行,在 _post_teardown self._fixture_teardown() 文件中“/home/leonidsoputnyak/Документы/project/test_task/venv/lib/python3.7/site-packages/django/test/testcases.py”,第 1177 行,在 _fixture_teardown 连接[db_name].check_constraints() 文件中“/home /leonidsoputnyak/Документы/project/test_task/venv/lib/python3.7/site-packages/django/db/backends/sqlite3/base.py”,第 318 行,在 check_constraints bad_value、referenced_table_name、referenced_column_name django.db.utils 中。 IntegrityError:主键为“1”的表“course_participant”中的行具有无效的外键:course_participant.student_id 包含值“1”在 student.id 中没有对应的值。
有人可以解释为什么我的 StudentAssignTo Course APITestCase 测试失败以及我该如何解决它?
解决方案
测试失败,setUp
因为您尝试CourseParticipant
使用不存在的 student_id 值创建方法。所以你应该首先创建User
和Course
对象并使用它们的ID:
class StudentAssignToCourseAPITestCase(APITestCase):
def setUp(self):
self.student_obj = Student.objects.create(
first_name='test',
last_name='student',
email='test_student@gmail.com',
)
self.course_obj = Course.objects.create(
# couse's attribute here
)
student_obj = CourseParticipant.objects.create(
course_id=self.course_obj.pk,
student_id=self.student_obj.pk,
)
def test_create_item(self):
url = api_reverse('student:assign_student_to_course')
data = {
'course_id': self.course_obj.pk,
'student_id': self.student_obj.pk,
}
response = self.client.post(url, data, format='json')
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
self.assertEqual(Student.objects.count(), 2)
return response.data
推荐阅读
- c# - 如何正确处理对同一变量的并发访问?
- jquery - 在不离开当前页面的情况下使用 Ajax 提交表单
- python - 在游戏中保存循环迭代的结果
- html - 如何动态地使表格列宽适应最大列表组项的大小?CSS
- html - HTML/CSS 不向左移动
- r - 在R中,我将如何通过一个不能接受双精度的函数循环一个字符向量
- sql - 如何计算每个工作日(周一、周二等)的行数总计(count(*))
- julia - 在 Julia 0.7 中使用 linspace
- javascript - Chrome CORB 阻止 APIGateway lambda 请求
- c - 在不持有父执行的情况下获取子进程的返回值