如何成功传递一个 Json 来在 Django 中渲染和操作它?

Posted

技术标签:

【中文标题】如何成功传递一个 Json 来在 Django 中渲染和操作它?【英文标题】:How to successfully pass a Json to render and manipulate it in Django? 【发布时间】:2018-02-02 03:31:44 【问题描述】:

我正在尝试从 POST 请求返回 Json 响应,但在路径中遇到各种错误。

首先,我有以下观点

class ChartData8(APIView):
    def tickets_per_day_results(request):
        if request.method == "POST":
            template_name = 'personal_website/tickets_per_day_results.html'
            year = request.POST.get('select_year', None)
            week = request.POST.get('select_week', None)
            ....do stuff...
            data = "label_number_days": label_number_days,
                    "days_of_data": count_of_days
        return render(request,template_name,JsonResponse(data))

调用包含 Ajax 请求的模板 tickets_per_day_results.html

$.ajax(
    method: "POST",
    url: endpoint,
    dataType: 'json',
    contentType: "application/json",
    headers: "X-CSRFToken": $.cookie("csrftoken"),
    success: function(data)
        console.log(data)
        label_number_days = data.label_number_days
        days_of_data = data.days_of_data
        setChart()

    ,
    error: function(jqXHR,error_data, errorThrown)
        console.log("error on data")
        console.log(error_data)
        console.log(JSON.stringify(jqXHR))
        console.log("AJAX error: " + error_data + ' : ' + errorThrown)
    

但是这种组合会引发context must be a dict rather than JsonResponse 错误。

我尝试了各种替代方案:

替代方案 1: 我使用 Response 而不是 JsonResponse,如下所示:

class ChartData8(APIView):
    def tickets_per_day_results(request):
        if request.method == "POST":
            template_name = 'personal_website/tickets_per_day_results.html'
            year = request.POST.get('select_year', None)
            week = request.POST.get('select_week', None)
            ....do stuff...
            data = "label_number_days": label_number_days,
                    "days_of_data": count_of_days
        return render(request,template_name,Response(data))

但这抛出了错误context must be a dict rather than Response

替代方案 2: 我尝试将对象转换为如下所示的字典,而不是 JsonResponseResponse

class ChartData8(APIView):
    def tickets_per_day_results(request):
        if request.method == "POST":
            template_name = 'personal_website/tickets_per_day_results.html'
            year = request.POST.get('select_year', None)
            week = request.POST.get('select_week', None)
            ....do stuff...
            data = "label_number_days": label_number_days,
                    "days_of_data": count_of_days
        return render(request,template_name, dict(Response(data)))

但这抛出了错误The response content must be rendered before it can be iterated over

替代方案 3: 我尝试在没有 JsonResponseResponse 的情况下传递数据,而不是 1 和 2:

class ChartData8(APIView):
    def tickets_per_day_results(request):
        if request.method == "POST":
            template_name = 'personal_website/tickets_per_day_results.html'
            year = request.POST.get('select_year', None)
            week = request.POST.get('select_week', None)
            ....do stuff...
            data = "label_number_days": label_number_days,
                    "days_of_data": count_of_days
        return render(request,template_name, data)

但这会从 ajax 请求中抛出错误 parsererror,因为这意味着您只需返回一个字符串或另一个值,它并不是真正的 Json,因此解析器在解析它时会失败。您可以通过从 Ajax 请求中删除 dataType:'json' 来避免此错误(来自 parsererror Ajax 的解决方案),但这将不允许我从模板 tickets_per_day_results 操作我的数据集,即

删除dataType:json

$.ajax(
    method: "POST",
    url: endpoint,
    headers: "X-CSRFToken": $.cookie("csrftoken"),
    success: function(data)
        console.log(data)
        label_number_days = data.label_number_days
        days_of_data = data.days_of_data
        setChart()

    ,
    error: function(jqXHR,error_data, errorThrown)
        console.log("error on data")
        console.log(error_data)
        console.log(JSON.stringify(jqXHR))
        console.log("AJAX error: " + error_data + ' : ' + errorThrown)
    

那么我无法操作位于 Ajax 请求下方的数据集:

data: 
        labels: label_number_days,
        datasets :
            [
                label: 'User_001',
                data [days_of_data[0],days_of_data[1],days_of_data[2],days_of_data[3],days_of_data[4],days_of_data[5],days_of_data[6]],
                backgroundColor: 'rgba(255, 99, 132, 0.6)',
                borderColor: '#777',
                borderWidth: 1,
                hoverBorderWidth: 3,
                hoverBorderColor: '#000'
            ,

因为你找到了Uncaught TypeError: Cannot read property '0' of undefined

这是一条乏味的道路,我已经没有想法(和耐心)了。如果有人可以建议我任何其他选择,那么这将使我的健康得到一些缓解。

更新 每日票数结果 html 文件

% extends "personal_website/header.html"%

<script>
% block jquery %

var endpoint = '/tickets_per_day_results/' //This works with the chart_data view.

var days_of_data = []
var label_number_days = []

$.ajax(
    method: "POST",
    url: endpoint,
    dataType: 'json',
    contentType: "application/json",
    headers: "X-CSRFToken": $.cookie("csrftoken"),
    success: function(data)
        console.log(data)
        label_number_days = data.label_number_days
        days_of_data = data.days_of_data
        setChart()

    ,
    error: function(jqXHR,error_data, errorThrown)
        console.log("error on data")
        console.log(error_data)
        console.log(JSON.stringify(jqXHR))
        console.log("AJAX error: " + error_data + ' : ' + errorThrown)
    
)
function setChart()
var ctx_tickets_per_day       = document.getElementById("tickets_per_day")

var tickets_per_day = new Chart(ctx_tickets_per_day, 
    showTooltips: false,
    type:'bar',
    data: 
        labels: label_number_days,
        datasets :
            [
                label: 'Oscar Gil',
                data: [days_of_data[0],days_of_data[1],days_of_data[2],days_of_data[3],days_of_data[4],days_of_data[5],days_of_data[6]],
                backgroundColor: 'rgba(255, 99, 132, 0.6)',
                borderColor: '#777',
                borderWidth: 1,
                hoverBorderWidth: 3,
                hoverBorderColor: '#000'
            ,
            
                label: 'Oscar Rodriguez',
                data: [days_of_data[7],days_of_data[8],days_of_data[9],days_of_data[10],days_of_data[11],days_of_data[12],days_of_data[13]],
                backgroundColor: 'rgba(54, 162, 235, 0.6)',
                borderColor: '#777',
                borderWidth: 1,
                hoverBorderWidth: 3,
                hoverBorderColor: '#000'
            ,

            
                label: 'Animesh Rathore',
                data: [days_of_data[14],days_of_data[15],days_of_data[16],days_of_data[17],days_of_data[18],days_of_data[19],days_of_data[20]],
                backgroundColor: 'rgba(255, 206, 86, 0.6)',
                borderColor: '#777',
                borderWidth: 1,
                hoverBorderWidth: 3,
                hoverBorderColor: '#000'
            ,

            
                label: 'Bhaskar Sharma',
                data: [days_of_data[21],days_of_data[22],days_of_data[23],days_of_data[24],days_of_data[25],days_of_data[26],days_of_data[27]],
                backgroundColor: 'rgba(75, 192, 192, 0.6)',
                borderColor: '#777',
                borderWidth: 1,
                hoverBorderWidth: 3,
                hoverBorderColor: '#000'
            ,

            
                label: 'Victor Catacora',
                data: [days_of_data[28],days_of_data[29],days_of_data[30],days_of_data[31],days_of_data[32],days_of_data[33],days_of_data[34]],
                backgroundColor: 'rgba(153, 102, 255, 0.6)',
                borderColor: '#777',
                borderWidth: 1,
                hoverBorderWidth: 3,
                hoverBorderColor: '#000'
            ,

            
                label: 'Jimmy Gonzalez',
                data: [days_of_data[35],days_of_data[36],days_of_data[37],days_of_data[38],days_of_data[39],days_of_data[40],days_of_data[41]],
                backgroundColor: 'rgba(236, 115, 9, 1)',
                borderColor: '#777',
                borderWidth: 1,
                hoverBorderWidth: 3,
                hoverBorderColor: '#000'
            ,

            
                label: 'Piyush Gupta',
                data: [days_of_data[42],days_of_data[43],days_of_data[44],days_of_data[45],days_of_data[46],days_of_data[47],days_of_data[48]],
                backgroundColor: 'rgba(185, 29, 12, 0.6)',
                borderColor: '#777',
                borderWidth: 1,
                hoverBorderWidth: 3,
                hoverBorderColor: '#000'
            ,

            
                label: 'Carlos Prieto',
                data: [days_of_data[49],days_of_data[50],days_of_data[51],days_of_data[52],days_of_data[53],days_of_data[54],days_of_data[55]],
                backgroundColor: 'rgba(105, 129, 64, 0.6)',
                borderColor: '#777',
                borderWidth: 1,
                hoverBorderWidth: 3,
                hoverBorderColor: '#000'
            ,

            
                label: 'Daniel Estrada',
                data: [days_of_data[56],days_of_data[57],days_of_data[58],days_of_data[59],days_of_data[60],days_of_data[61],days_of_data[62]],
                backgroundColor: 'rgba(15,  199, 84, 0.6)',
                borderColor: '#777',
                borderWidth: 1,
                hoverBorderWidth: 3,
                hoverBorderColor: '#000'
            ,

            ]
        ,
        options: 
          scales: 
            yAxes: [
                ticks: 
                    beginAtZero: true
                
            ]
          ,

          title: 
            display: true,
            text: 'Tickets by engineer per day',
            fontSize: 30
            ,
        legend: 
            position: 'right',
            display: true,
            labels: 
                fontColor: '#000'
                
            ,
            layout: 
                padding: 
                    left: 50,
                    right: 0,
                    bottom: 0,
                    top: 0
                    
            ,
            tooltips: 
              enabled: true
            ,

          hover : 
            animationDuration: 0
          ,

          animation: 
            duration: 0.8,
            onComplete: function()
                var chartInstance = this.chart,
                ctx = chartInstance.ctx;
                Chart.defaults.global.defaultFontColor = '#777';
                ctx.font = Chart.helpers.fontString(Chart.defaults.global.defaultFontSize,
                           Chart.defaults.global.defaultFontStyle, Chart.defaults.global.defaultFontFamily);
                ctx.textAlign = 'center';
                ctx.textBaseline = 'bottom';

                this.data.datasets.forEach(function (dataset, i) 
                var isHidden = dataset._meta[0].hidden; //'hidden' property of dataset
                if (!isHidden)  //if dataset is not hidden
                    var meta = chartInstance.controller.getDatasetMeta(i);
                    meta.data.forEach(function (bar, index) 
                        var data = dataset.data[index];
                        ctx.fillText(data, bar._model.x, bar._model.y - 5););
                    );
            
          
        
    )


% endblock %

    % block content %

<div class ='row'>

    % csrf_token %
<div class="col-sm-12" url-endpoint='% url "tickets_per_day_results" %'>
        <div>
            <canvas id="tickets_per_day"  ></canvas>
        </div>
</div>
</div>
 % endblock content %

【问题讨论】:

【参考方案1】:

我认为您在以 JSON 格式返回数据时使用了错误的方法。 在代码中:

render(request,template_name,JsonResponse(data))

在 Django here 的文档中。渲染快捷方式用于渲染带有字典数据的 Html 模板以更新页面。

根据 django 代码,我猜你使用的是 Django rest 框架。 为了发送 JSON 数据,您应该使用此处的示例 DRF example response 以便将 JSON 数据发送到页面。

【讨论】:

但是如何用模板渲染数据呢? 为了呈现模板中的数据,您必须删除 JsonResponse(data),并只放置数据。 问题是,如果我只放data,那么我会遇到parsererror 问题,为了避免这种情况,我必须删除dataType: 'json,这样做会导致Uncaught TypeError: Cannot read property '0' of undefined 您能否分享您的模板“personal_website/tickets_per_day_results.html”来看看。 好的,我看的更清楚了,您正在通过 ajax 调用使用 post 方法。并且您不应该使用 render 作为请求的返回。在您完成的 post 方法上直接使用“return JsonResponse(data)”

以上是关于如何成功传递一个 Json 来在 Django 中渲染和操作它?的主要内容,如果未能解决你的问题,请参考以下文章

如何将数据从回调传递到Django中的另一个视图?

如何将 JSON 传递给 Django 中的 Ajax 请求?

Django - 在 URL 中为 API 调用传递 json 或数组

如何在 Django 模板上传递 Python 列表并在 JavaScript 中使用它?

在 Django 中使用 HttpResponseRedirect 时如何传递模板上下文信息?

通过jQuery ajax调用将值列表传递给django视图