quiero devolver los nombres de un producto en distintos, y también he usado agregados para algunos cálculos
estos son mis modelos.py
class CustomerInvoice(models.Model): customer = models.CharField(max_length=50) items = models.ManyToManyField(Product,through='ProductSelecte') date = models.DateTimeField(auto_now_add=True) class ProductSelecte(models.Model): product = models.ForeignKey(Product, on_delete=models.CASCADE) products= models.ForeignKey(CustomerInvoice,on_delete=models.CASCADE,related_name='product') qnt= models.IntegerField(default=1) price = models.IntegerField() cash = models.IntegerField()
quiero hacer una tabla para rastrear la actividad de los clientes
y esta es mi consulta
context['clients'] = ProductSelecte.objects.filter( products__customer=self.object.name).values('product').annotate(quantity=Sum(F('qnt'))).order_by('product')
hasta aquí funciona bien, pero también necesito agregar el precio usando esto
.aggregate( total_price=Sum(F('price')))
levanta este error
El objeto 'dict' no tiene atributo 'order_by'
Gracias por tu ayuda
ACTUALIZAR
por ejemplo, en la primera factura de john 4th june john bought two pen price:20$ with 3 book price : 30$ total price for this invoice :50$
, y para la segunda factura 5th july he buy 1 pen price:10$ with 2 copybook price:20$ total price:30
, necesito un resultado como este
client : john , activities : 3 pen(total pens he bought till now),price pens : 30 (total pens price he bought till now) , 3 book(total books he bought till now) ; price:30(total books price he bought till now) ,2 copybook ;price:20 and then total price of both invoice : 30+50 = 80
Debe hacer la anotación por cliente por producto y luego realizar alguna "agrupación" a nivel de Django/Python:
from django.db.models import F, Sum from itertools import groupby from operator import itemgetter qs = ProductSelecte.objects.values( customer=F('products__customer') product=F('product') ).annotate(quantity=Sum('qnt')).order_by('customer', 'product') data = { k: list(vs) for k, vs in groupby(qs, itemgetter('customer')) }
Aquí data
son un diccionario que asigna el nombre del customer
a una lista de diccionarios que contienen la identificación del product
, el nombre del cliente y la quantity
.
Si lo pasa a la plantilla, puede, por ejemplo, renderizar esto con:
<ul> {% for c, vs in data.items %} <li>{{ c }}</li> <ul> {% for v in vs %} <li>{{ v.product }}: {{ v.quantity }}</li> {% endfor %} </ul> {% endfor %} </ul>
EDITAR : en función de la solicitud actualizada, debe realizar una anotación y una solicitud agregada:
class ProfileClientDetailView(LoginRequiredMixin,DetailView): # … def get_object(self): return get_object_or_404(Client,pk=self.kwargs['pk']) def get_context_data(self,*args,**kwargs): data = super().get_context_data(*args,**kwargs) data['products'] = ProductSelecte.objects.filter( products__customer=self.object.name ).values('product').annotate( quantity=Sum('qnt'), total_price=Sum('price') ).order_by('product') data['total'] = ProductSelecte.objects.filter( products__customer=self.object.name ) .aggregate( quantity=Sum('qnt'), total_price=Sum('price') ) return data
Entonces se puede representar como:
<ul> {% for pr in products %} <li>{{ pr.product }}: {{ pr.total_price }} ({{ pr.quantity }} items)</li> </ul> TOTAL: {{ total.total_price }} ({{ total.quantity }} items)