Issue
So, this is something a little crazy, but I hope it has a solution. I am creating a web application to check sales on a publishing house. Up until now I got everything good: I created a model for products (books), for sales... Everything OK. I am using charts.js to display data. Here is the code for the view:
def top_sales_view (request, *args, **kwargs):
labels = [] #list for charts.js
sold_copies = [] #list for charts.js
billed = [] #list for charts.js
books_all = Product.objects.all() #get all data from books
for book in books_all:
book_data=Sale.objects.filter(book = book.id ) #get all sales per book
quantity_list = [] #set list of each quantity per sale
income_list=[] #set list of each income per sale
for data in book_data:
quantity = data.quantity
income = float(data.final_price)
quantity_list.append(quantity) #list all quantity sales per book
copies=sum(quantity_list) #sum all quantity sales per book
income_list.append(income) #list all income sales per book
billing=sum(income_list) #sum all income sales per book
book ={
'id': book.id,
'title':book.title,
'cost_center': book.cost_center,
'data' : {
'copies': copies,
'billing' : billing
}
}
#------------- PARA CHARTS.JS -------------
if book['cost_center'] not in labels: #chech if cost_center is not on the list
labels.append(book['cost_center']) #if it isn't, add it
if book['cost_center'] in labels:
sold_copies.append(book['data']['copies'])
print (sold_copies)
my_context = {
'labels': labels,
'copies': sold_copies,
'billing': billed,
}
return render (request, "top-ventas.html", my_context)
The deal is that, there are two separate books, because one is the second edition of the first one, so they account it as separate books, but they have the same cost center value (as all income goes to cover the same "project", let's say). My question is: is there an effecient way to get book['data']['copies']
and book['data']['billing']
, check if its correspondent cost center is in the labels
list, and add/sum it so, even though they are different books they sum for the chart? I am not sure if I am making myself clear.
Edit: Added Models.
Sales
class Sale (models.Model):
def __str__(self):
if self.electronic_bill == True:
return "FE" + str(self.bill)
else:
return str(self.bill)
bill = models.IntegerField()
electronic_bill = models.BooleanField(default=True, blank=True, null=True,)
type_options =(
("L", "librería"),
("D", "directo"),
("F", "feria"),
("V", "venta de derechos"),
("A", "apoyos y becas"),
("E", "charlas y eventos"),
("w", "ventas web"),
)
type = models.CharField(max_length=120, null=True, choices=type_options)
client = models.CharField(max_length=120, null=True, blank=True)
date = models.DateField(null=True, blank=True, )
book = models.ForeignKey (Product, on_delete=models.CASCADE, null=True, blank=True)
cost_center = models.CharField(max_length=120, null=True, choices=Product.cost_center_options)
quantity = models.IntegerField(blank=True,null=True)
unit_price = models.IntegerField (blank=True,null=True)
discount = models.IntegerField(blank=True,null=True)
final_price = models.FloatField(blank=True,null=True)
Product:
class Product (models.Model):
def __str__(self):
return self.title
isbn = models.IntegerField(blank=True, null=True)
title = models.CharField(max_length=200, blank=True, null=True)
cost_center_options =(
("01T001", "El secreto del alma número diez"),
("01T002", "Un lápiz labial para una momia"),
("01T003", "Sobre el horror"),
("01T004", "El tambor encantado"),
("01T005", "Historia de una vieja geisha"),
("01T006", "El hombre que dejó de respirar"),
("01IL001", "No tengo ni puta idea de arte"),
("01IL002", "Del mismo modo en el sentido contrario"),
("01IL003", "La cólera en los tiempos del amor"),
("01IL004", "Título pendiente"),
("01IL005", "Cuentos para el desconfinamiento"),
("02S007", "Daruma"),
)
cost_center = models.CharField(max_length=120, null=True, choices=cost_center_options)
authors = models.ManyToManyField(to="Author", related_name="autor", blank=True)
illustrators = models.ManyToManyField(to="Author", related_name="ilustrador", blank=True)
translators = models.ManyToManyField(to="Author", related_name="traductor", blank=True)
price = models.FloatField(blank=True, null=True)
Solution
For your chart.js to work I noticed that you only need:
labels = [] # cost_center list of the books that have been saled
sold_copies = [] # quantity of copies of those books
billing = [] # how much money did those books sell
So then, you can use Django's ORM to retrieve the results on a cleaner and faster way:
from django.db.models import Sum
top_sales_qs = Product.objects.annotate(
bill=Sum('sale__bill'), copies=Sum('sale__quantity')
).order_by('-bill').values_list('cost_center', 'copies', 'bill')
To group them by center_cost
value, you can do:
labels_dict = {}
for label, copies, bill in top_sales_qs:
current_val = labels_dict.get(label)
if current_val is None:
current_val = [label, 0, 0]
current_label, current_copies, current_bill = current_val
new_copies = current_copies + copies
new_bill = current_bill + bill
labels_dict[label] = [label, new_copies, new_bill]
Then to get the lists for the chart.js
labels, sold_copies, billing = list(zip(*labels_dict.values()))
Answered By - mendespedro
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.