2014-10-19 16 views
16

Django ve D3.js. kullanarak çok basit bir çubuk grafik yazmaya çalışıyorum. Tarih denilen datetime alanına sahip bir oyunum var. Yapmak istediğim, aylara göre gruplandırılmış oyunların sayısını göstermek. Temelde iki soru var: Bunları o ay içinde dinleme sayısı sayısı ile beraber aya göre gruplandırılmış olsun yapmak nasılVeri Django'dan D3'e aktarılıyor

  1. D3 tarafından kullanılabilir bir hale Django bu bilgiyi almanın en iyi yolu nedir
  2. .

Şimdi burada bazı diğer cevaplar baktım ve denedim

json = (Play.objects.all().extra(select={'month': "extract(month FROM date)"}) 
.values('month').annotate(count_items=Count('date'))) 

Bu istediğim trhe bilgilere yaklaştığında ama şablonda çıktı bunu çalıştığınızda aşağıdaki olarak ortaya çıkıyor Ayların sonunda (Ls ile). Bu açıkça geçerli js (qoutes yok) anlamına gelmez ve gerçekten de L'lerin orada olmasını istemiyorum.

Şablon:

<script> 
     var test ={{ json|safe }}; 
     alert("test"); 

    </script> 

çıkışı:

var test = [{'count_items': 10, 'month': 1L}, {'count_items': 5, 'month': 2L}]; 

Ben de bu verilere json.dumps denedi ama geçerli JSON değil söyledim olsun. Bu, Django'da yapılması çok daha kolay olması gerektiği gibi hissediyor, bu yüzden belki de yolun sonuna doğru ilerliyorum.

+0

Django 1.7 kullanıyor musunuz: yardımcı olmak amacıyla, github üzerinde, örnek bir projeye hep birlikte dosyaları koyduk? Aynı sürümü kullandığımızı doğrulamak için zaten size özel bir çözümüm var. –

+0

1.4.1 Yükseltme konuştuğumuzda ve sonra cevabınızı deneyeceğim. –

+0

Tamam. Çünkü [django.http.JsonResponse] (https://docs.djangoproject.com/en/dev/ref/request-response/#jsonresponse-objects) 1.7'de tanıtıldı. –

cevap

47

D3.js v3 ürününün methods to load data from external resources numaralı güzel bir koleksiyonu var ¹, Verilerinizi sayfanıza yerleştirmemeniz daha iyidir, sadece yükleyin.

Bu örnek bir cevap olacaktır.

en model tanımı ile başlayalım:

# models.py 
from django.db import models 


class Play(models.Model): 
    name = models.CharField(max_length=100) 
    date = models.DateTimeField() 

Bir urlconf: Biz iki URL'ler, bir html (görünüm) dönmek ve diğer url kullanıyor

# urls.py 
from django.conf.urls import url 


from .views import graph, play_count_by_month 

urlpatterns = [ 
    url(r'^$', graph), 
    url(r'^api/play_count_by_month', play_count_by_month, name='play_count_by_month'), 
] 

(görünümü play_count_by_month) yalnızca verileri JSON olarak döndürmek için bir api olarak.

Ve nihayet görüşlerimiz: Ben SQLite ile testler yaptım beri

# views.py 
from django.db import connections 
from django.db.models import Count 
from django.http import JsonResponse 
from django.shortcuts import render 

from .models import Play 


def graph(request): 
    return render(request, 'graph/graph.html') 


def play_count_by_month(request): 
    data = Play.objects.all() \ 
     .extra(select={'month': connections[Play.objects.db].ops.date_trunc_sql('month', 'date')}) \ 
     .values('month') \ 
     .annotate(count_items=Count('id')) 
    return JsonResponse(list(data), safe=False) 

Burada, ben veritabanı agnostik olmak için ekstra değişti unutmayın, JSON olarak bizim veri döndürmek için bir görünümü tanımladı.

Ve ay çalma sayıları bir grafiğini göstermektedir bizim graph/graph.html şablonu aşağıdaki gibidir:

<!DOCTYPE html> 
<meta charset="utf-8"> 
<style> 

body { 
    font: 10px sans-serif; 
} 

.axis path, 
.axis line { 
    fill: none; 
    stroke: #000; 
    shape-rendering: crispEdges; 
} 

.x.axis path { 
    display: none; 
} 

.line { 
    fill: none; 
    stroke: steelblue; 
    stroke-width: 1.5px; 
} 

</style> 
<body> 
<script src="http://d3js.org/d3.v3.js"></script> 
<script> 

var margin = {top: 20, right: 20, bottom: 30, left: 50}, 
    width = 960 - margin.left - margin.right, 
    height = 500 - margin.top - margin.bottom; 

var parseDate = d3.time.format("%Y-%m-%d").parse; // for dates like "2014-01-01" 
//var parseDate = d3.time.format("%Y-%m-%dT00:00:00Z").parse; // for dates like "2014-01-01T00:00:00Z" 

var x = d3.time.scale() 
    .range([0, width]); 

var y = d3.scale.linear() 
    .range([height, 0]); 

var xAxis = d3.svg.axis() 
    .scale(x) 
    .orient("bottom"); 

var yAxis = d3.svg.axis() 
    .scale(y) 
    .orient("left"); 

var line = d3.svg.line() 
    .x(function(d) { return x(d.month); }) 
    .y(function(d) { return y(d.count_items); }); 

var svg = d3.select("body").append("svg") 
    .attr("width", width + margin.left + margin.right) 
    .attr("height", height + margin.top + margin.bottom) 
    .append("g") 
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); 

d3.json("{% url "play_count_by_month" %}", function(error, data) { 
    data.forEach(function(d) { 
    d.month = parseDate(d.month); 
    d.count_items = +d.count_items; 
    }); 

    x.domain(d3.extent(data, function(d) { return d.month; })); 
    y.domain(d3.extent(data, function(d) { return d.count_items; })); 

    svg.append("g") 
     .attr("class", "x axis") 
     .attr("transform", "translate(0," + height + ")") 
     .call(xAxis); 

    svg.append("g") 
     .attr("class", "y axis") 
     .call(yAxis) 
    .append("text") 
     .attr("transform", "rotate(-90)") 
     .attr("y", 6) 
     .attr("dy", ".71em") 
     .style("text-anchor", "end") 
     .text("Play count"); 

    svg.append("path") 
     .datum(data) 
     .attr("class", "line") 
     .attr("d", line); 
}); 

</script> 
</body> 
</html> 

Bu, bu (rastgele verilerle) gibi güzel grafik döndürür: Graph of Play counts by month

Güncelleme 1: D3 v4, harici bir dosyaya harici bir veri yüklemek için kodu hareket ettirecektir, lütfen bkz. d3-request. Güncelleme 2: github.com/fgmacedo/django-d3-example

+0

Hmmm bu yüzden hepsini bir araya getirmeyi denedim ve elde ettiğim şey grafiğin sol kısmı (çizgiler veya etiketler). Burada benim play_count_by_month sayfa çıktısı şöyle görünüyor: '[{" count_items ": 10," ay ":" 2013-01-01T00: 00: 00Z "}, {" count_items ": 5," month ":" 2013-02-01T00: 00: 00Z "}]' Herhangi bir JS hatası veya ağ tarafında herhangi bir sorun görmedim (istekte bulunulduğu anlaşılıyor gibi görünüyor) –

+1

Tarih formatıyla ilgili bir sorun var. 'Play_count_by_month' sonucum şöyle: '[{" count_items ": 731," month ":" 2014-01-01 "}, {" count_items ": 404," month ":" 2014-02-01 " }] '. Graph.html'deki "parseDate" işlevini şu şekilde değiştirmeyi deneyebilirsiniz: var parseDate = d3.time.format ("% Y-% m-% dT00: 00: 00Z"). Ayrıştırma; ' –

+0

Bu işe yaradı! çok teşekkürler. –

İlgili konular