AssertionError: 302 != 200 : Couldn't retrieve redirection page '/api/v2/app/nextdialog': response code was 302 (expected 200)

AssertionError: 302 != 200 : Couldn't retrieve redirection page '/api/v2/app/nextdialog': response code was 302 (expected 200)

AssertionError: 302 != 200: 无法检索重定向页面“/api/v2/app/nextdialog”:响应代码为 302(预期为 200)

在 Django 中可以有三个视图,每个视图都重定向到下一个。视图 1 重定向到视图 2,视图 2 重定向到视图 3?

Views.py:

class ConversationLayerView(generics.GenericAPIView):
    permission_classes = (permissions.IsAuthenticated,)

    def post(self, request, *args, **kwargs):
        body = request.data
        cardType = body["cardType"]
        if cardType == "CHOICE":
            serializer = appChoiceTypeSerializer(body)
        elif cardType == "TEXT":
            serializer = appTextTypeSerializer(body)
        elif cardType == "INPUT":
            serializer = appInputTypeSerializer(body)
        else:
            serializer = StartAssessmentSerializer(body)
        validated_body = serializer.validate_value(body)
        url = get_endpoint(validated_body)
        reverse_url = encodeurl(body, url)
        return HttpResponseRedirect(reverse_url)
        

class NextDialog(generics.GenericAPIView):
    permission_classes = (permissions.AllowAny,)

    def get(self, request, *args, **kwargs):
        result = request.GET
        data = result.dict()
        contact_uuid = data["contact_uuid"]
        step = data["step"]
        value = data["value"]
        description = data["description"]
        title = data["title"]

        if data["cardType"] == "CHOICE":
            optionId = int(value) - 1
        else:
            optionId = data["optionId"]
        path = get_path(data)
        assessment_id = path.split("/")[-3]
        request = build_rp_request(data)
        app_response = post_to_app(request, path)
        if data["cardType"] != "TEXT":
            if data["cardType"] == "INPUT":
                optionId = None
            store_url_entry = appAssessments(
                contact_id=contact_uuid,
                assessment_id=assessment_id,
                title=title,
                description=description,
                step=step,
                user_input=value,
                optionId=optionId,
            )
            store_url_entry.save()
        pdf = pdf_ready(app_response)
        if pdf:
            response = pdf_endpoint(app_response)
            return HttpResponseRedirect(response)
        else:
            message = format_message(app_response)
            return Response(message, status=status.HTTP_200_OK)
            
            
class Reports(generics.GenericAPIView):
    permission_classes = (permissions.AllowAny,)

    def get(self, request, *args, **kwargs):
        report_id = request.GET.get("report_id")
        response = get_report(report_id)
        return Response(response, status=status.HTTP_200_OK)                    
        
    

Utils.py

def get_endpoint(payload):
   value = payload["value"]
   if value != "":
       if value == "back":
           url = reverse("app-previous-dialog")
       elif value == "abort":
           url = reverse("app-abort")
       else:
           url = reverse("app-next-dialog")
   elif value == "":
       url = reverse("app-start-assessment")
   return url

def encodeurl(payload, url):
   qs = "?" + urlencode(payload, safe="")
   reverse_url = url + qs
   return reverse_url

代码解释: 该应用程序在 ConversationLayerView 中接收 json 负载。它调用端点方法以根据有效负载中设置的 'value' 键知道要重定向到哪个端点。

请求看起来像这样:

{
    "contact_uuid": "67460e74-02e3-11e8-b443-00163e990bdb",
    "choices": null,
    "value": "Charles",
    "cardType": "INPUT",
    "step": null,
    "optionId": null,
    "path": "",
    "title": "",
    "description": "What's your name",
    "message": ""
}

由于“value”是“Charles”,视图重定向到 NextDialog 视图中的“app-next-dialog”。 在此视图中,向外部应用程序发出 POST 请求并收到 json 响应。如果响应具有 PDF 键,则此视图将重定向到第三个视图。 这发生在这里:

if pdf:
    response = pdf_endpoint(app_response)
    return HttpResponseRedirect(response)
else:
    message = format_message(app_response)
    return Response(message, status=status.HTTP_200_OK)

如果密钥存在,则重定向到输出为“/api/v2/app/reports?report_id=/reports/17340f51604cb35bd2c6b7b9b16f3aec”的“response”,否则不重定向,而是 return 200 .

错误:

AssertionError: 302 != 200 : Couldn't retrieve redirection page '/api/v2/app/nextdialog': response code was 302 (expected 200)

Url.py

path(
    "api/v2/app/assessments",
    views.PresentationLayerView.as_view(),
    name="app-assessments",
),
path("api/v2/app/nextdialog", views.NextDialog.as_view(), name="app-next-dialog"),
path("api/v2/app/reports", views.Reports.as_view(), name="app-reports"),

test_views.py:

class appAssessmentReport(APITestCase):
    data = {
        "contact_uuid": "67460e74-02e3-11e8-b443-00163e990bdd",
        "choices": None,
        "message": (
            "How old are you?\n\nReply *back* to go to "
            "the previous question or *abort* to "
            "end the assessment"
        ),
        "explanations": "",
        "step": 39,
        "value": "27",
        "optionId": None,
        "path": "/assessments/f9d4be32-78fa-48e0-b9a3-e12e305e73ce/dialog/next",
        "cardType": "INPUT",
        "title": "Patient Information",
        "description": "How old are you?",
    }

    start_url = reverse("app-assessments")
    next_dialog_url = reverse("app-next-dialog")
    pdf_url = reverse("app-reports")
    
    destination_url = (
        "/api/v2/app/nextdialog?contact_uuid="
        "67460e74-02e3-11e8-b443-00163e990bdd&"
        "choices=None&message=How+old+are+you%3F"
        "%0A%0AReply+%2Aback%2A+to+go+to+the+"
        "previous+question+or+%2Aabort%2A+to+end"
        "+the+assessment&explanations=&step="
        "39&value=27&optionId=None&path=%2F"
        "assessments%2Ff9d4be32-78fa-48e0-b9a3"
        "-e12e305e73ce%2Fdialog%2Fnext&cardType"
        "=INPUT&title=Patient+Information&"
        "description=How+old+are+you%3F"
    )
    
    @patch("app.views.pdf_ready")
    @patch("app.views.post_to_app")
    def test_assessment_report(self, mock_post_to_app, mock_pdf_ready):
        mock_post_to_app.return_value = {
            "cardType": "CHOICE",
            "step": 40,
            "title": {"en-US": "YOUR REPORT"},
            "description": {"en-US": ""},
            "options": [
                {"optionId": 0, "text": {"en-US": "Option 1"}},
                {"optionId": 1, "text": {"en-US": "Option 2"}},
                {"optionId": 2, "text": {"en-US": "Option 3"}},
            ],
            "_links": {
                "self": {
                    "method": "GET",
                    "href": "/assessments/898d915e-229f-48f2-9b98-cfd760ba8965",
                },
                "report": {
                    "method": "GET",
                    "href": "/reports/17340f51604cb35bd2c6b7b9b16f3aec",
                },
            },
        }
        mock_pdf_ready.return_value = utils.pdf_ready(mock_post_to_app.return_value)
        user = get_user_model().objects.create_user("test")
        self.client.force_authenticate(user)
        response = self.client.post(self.start_url, self.data, format="json")
        print(response)
        self.assertRedirects(response, self.destination_url)

到目前为止这不起作用。总之,我只是想从视图 1 开始,重定向到视图 2,然后从视图 2 重定向到视图 3。 这在 Django 中可能吗? 谢谢。

问题出在你的测试上,而不是出在视图逻辑上——完全有可能有一个重定向链。

assertRedirects 检查响应的状态,默认情况下要求它是 HTTP 200 响应。因为你有一个重定向链,响应是 302(另一个重定向)而不是 200,这就是为什么测试失败并显示错误“响应代码是 302(预期 200)”。

您需要修改 target_status_code 参数以告知 assertRedirects 您期望响应具有 302 状态代码:

self.assertRedirects(response, self.destination_url, target_status_code=302)