Django REST框架。 APITestCase。如何修复'bad_value,referenced_table_name,referenced_column_name'

时间:2019-07-04 17:56:24

标签: django unit-testing django-rest-framework

我有以下型号:

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:

  

回溯(最近通话最近):     在调用中的第274行中,文件“/home/leonidsoputnyak/Документы/project/test_task/venv/lib/python3.7/site-packages/django/test/testcases.py”       self._post_teardown()     _post_teardown中的第1009行,文件“/home/leonidsoputnyak/Документы/project/test_task/venv/lib/python3.7/site-packages/django/test/testcases.py”       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中       坏值,引用表名称,引用列名称   django.db.utils.IntegrityError:表'course_participant'中具有主键'1'的行具有无效的外键:course_participant.student_id包含的值'1'在student.id中没有相应的值。

有人可以解释为什么我从StudentAssignTo课程APITestCase进行的测试失败以及我如何解决该问题吗?

1 个答案:

答案 0 :(得分:2)

在尝试使用不存在的student_id值创建setUp的{​​{1}}方法中,测试失败。因此,您应该首先创建CourseParticipantUser对象并使用其ID:

Course