I have the following models:
class Materiale(models.Model):
sottocategoria = models.ForeignKey(Sottocategoria, on_delete=models.CASCADE, null=True)
quantita=models.DecimalField(')
prezzo=models.DecimalField()
data=models.DateField(default="GG/MM/YYYY")
I wanna calculate the value given by the following expressions PREZZO*QUANTIA in a monthly's view (in other words the total sum of PRZZO*QUANTITA of all items in a single month), but my code does not work:
Monthly_views=Materiale.objects.filter(data__year='2020').values_list('month').annotate(totale_mensile=F(('quantita')*F('prezzo')))
Use values() method instead of values_list()
from django.db.models import F, Sum
result = Materiale.objects.annotate(totale_mensile=F('quantita') * F('prezzo')
).values('data__month').annotate(totale_mensile_sum=Sum('totale_mensile')))
or simply
result = Materiale.objects.values('data__month').annotate(totale_mensile_sum=Sum(F('quantita') * F('prezzo')))
Try filtering by month also
Monthly_views=Materiale.objects.filter(data__year='2020').filter(data_month='4')
Related
I connect multiple queryset from different objects into one list:
query_1 = Room.objects.all()
query_2 = Apartment.objects.all()
query_3 = Plot.objects.all()
all_user_objects = list(chain(query_1, query_2, query_3))
How can I add a sort by created_at date from the newest?
I try this:
all_user_objects.order_by('-created_at')
and this:
from operator import attrgetter
all_user_objects = list(chain(query_1, query_2, query_3), key=attrgetter('-created_at'))
You can use sorted() for this:
from operator import attrgetter
all_user_objects = list(sorted(chain(query_1, query_2, query_3), key=attrgetter('created_at'), reverse=True))
I want to get a specific date like "8" out of (2021-8-3) but it's showing like this image
how can I extract the specific date?
usertime = User.objects.filter(groups__name = 'patient').values('date_joined').annotate(date_only=Cast('date_joined', DateField()))
from django.db.models import F, Func,Value, CharField
usertime = (User.objects.filter(groups__name = 'patient').values('date_joined')
.annotate(date_only=Func(
F('date_joined'),
Value('MM'),
function='to_char',
output_field=CharField()
)
).values('date_only'))
Try this,
got a reference from #Yannics answer at: https://stackoverflow.com/a/60924664/5804947
you can further use YYYY / DD for years/date respectively under the Value field and works fine when the PostgreSQL database is used.
ANOTHER METHOD
from django.db.models.functions import Extract
usertime = User.objects.filter(groups__name = 'patient').values('date_joined').annotate(date_only=Extract('date_joined', 'month'))
I am trying to do a chart. My database has created_date. I am getting product data every day about 150 times and I want to see a daily increase and decrease of my data. I have no problem with my front end and Django-template (I try manual data and it works well) I just want to see the last 7 days chart.
When I use Products.objects.filter(created_dates=days) filter method I am getting empty Queryset.
I already try created_dates__gte=startdate,created_dates__lte=enddate it return empty Queryset to.
I also try created_dates__range to there is no answer too.
I just get data from created_dates__gte=days but I don't want these data.
view.py
from datetime import date,timedelta
import datetime
def data_chart(request):
data = []
week_days = [datetime.datetime.now().date()-timedelta(days=i) for i in range (1,7)]
for days in week_days:
product_num = Products.objects.filter(created_dates=days)
date =days.strftime("%d.%m")
item = {"day": date,"value":len(product_num)}
data.append(item)
return render(request, 'chartpage.html', {'data': data})
In my database, I have thousands of data and my daily data about 150. My created_dates column format like this.
created_dates col:
2020-10-19 09:39:19.894184
So what is wrong with my code?. Could you please help?
You are trying to compare DateTimeField type (created_dates) with Date type (week_days is list of days) so maybe You should try __date lookup.
product_num = Products.objects.filter(created_dates__date=days)
https://docs.djangoproject.com/en/3.0/ref/models/querysets/#date
Furthermore maybe You should consider start using Count() database function with group by instead of iterating over days.
Here is great explanation:
https://stackoverflow.com/a/19102493/5160341
You should be able to do this with a single aggregation query:
import datetime
from django.db.models import Count
def data_chart(request):
cutoff = datetime.date.today() - datetime.timedelta(days=7)
raw_data = (
Products.objects.filter(created_dates__gte=cutoff)
.values_list("created_dates__date")
.annotate(count=Count("id"))
.values_list("created_dates__date", "count")
)
data = [{"day": str(date), "value": value} for (date, value) in raw_data]
return render(request, "chartpage.html", {"data": data})
In the following queryset I am filtering planned hours per week (displayval is my week in this queryset) by employee. I would like to add an item for planned hours = 0 when the employee has no hours planned for a week I'm filtering by.
What's the easiest way to achieve this?
def DesignHubR(request):
emp3_list = Projectsummaryplannedhours.objects.values_list('displayval', 'employeename')
.filter(businessunit='a')
.filter(billinggroup__startswith='PLS - Project')
.filter(Q(displayval=sunday2)|Q(displayval=sunday))
.annotate(plannedhours__sum=Sum('plannedhours'))
emp3 = map(lambda x: {'date': x[0], 'employee_name': x[1], 'planned_hours': x[2]}, emp3_list)
context = {'sunday': sunday, 'sunday2': sunday2, 'emp3': emp3}
return render(request,'department_hub_ple.html', context)
I think that you can use the Coalesce(*expressions, **extra) function to solve your problem.
Accepts a list of at least two field names or expressions and returns the first non-null value (note that an empty string is not considered a null value).
So your query will be looking like:
from django.db.models import Sum, Value
from django.db.models.functions import Coalesce
emp3_list = \
Projectsummaryplannedhours.objects.\
filter(
Q(businessunit='a') &
Q(billinggroup__startswith='PLS - Project') &
(Q(displayval=sunday2) | Q(displayval=sunday))
).\
annotate(plannedhours__sum=Coalesce(
Sum('plannedhours'), Value(0)
)
).\
values_list('displayval', 'employeename')
See https://docs.djangoproject.com/en/1.9/ref/models/database-functions/#coalesce for more information.
This will help you to get plannedhours__sum = 0 if no entries to sum exists. If you also want to add additional parameter to each entry where plannedhours__sum = 0 you can use Django conditional expression.Read about Case expression for more information (https://docs.djangoproject.com/en/1.11/ref/models/conditional-expressions/#case).
Case() accepts any number of When() objects as individual arguments. Other options are provided using keyword arguments. If none of the conditions evaluate to TRUE, then the expression given with the default keyword argument is returned. If a default argument isn’t provided, None is used.
from django.db.models import Sum, Value, IntegerField
from django.db.models.functions import Coalesce
emp3_list = \
Projectsummaryplannedhours.objects.\
filter(
Q(businessunit='a') &
Q(billinggroup__startswith='PLS - Project') &
(Q(displayval=sunday2) | Q(displayval=sunday))
).\
annotate(plannedhours__sum=Coalesce(
Sum('plannedhours'), Value(0)
),
x=Case(When(plannedhours__sum=0, then=Value(0)),
output_field=IntegerField())
).\
values_list('displayval', 'employeename')
This will give you additional parameter x equals 0 if planned hours = 0 and None elsewhere. You can also filter emp3_list by annotated values.
As a result you can pass your queryset to a template context = {'sunday': sunday, 'sunday2': sunday2, 'emp3': emp3_list}, iterate over it there and get the attributes you need:
for q in emp3_list:
print(q[0], q[1], q[2])
Hope it will help you.
I have two lists, each is made up of objects having a date. I am trying to combine them and then order by date:
combined = invoices + payments
combined.sort(key = lambda x: x.date)
All well and good. However, if there is both an invoice object and payment object on the same day, I want the payment to be placed in the list before the invoice.
Just do this instead:
combined = payments + invoices
python iterable.sort method is guaranteed to be stable. (See python docs on standar types, 5.6.4 note 9)
That means if there are 2 elements a and b on your list such that key(a) == key(b), then they'll keep their relative order (that means, if a was placed before b on the unsorted list, it'll still be like that after it's sorted).
You should be able to do something like this to get the sorting you want:
combined.sort(key = lambda x: (x.date, 1 if x in invoices else 0))
The idea being that, as long as the objects are distinct, you can create a sorting tuple that includes an indicator of which list the object came from. That'll make it sort by the dates first, then fall over to the 2nd field if the dates match.
In addition to key=, you can also use cmp= in the sort function.
class Invoice(object):
P = 1
def __init__(self, date):
self.date = date
class Payment(object):
P = 0
def __init__(self, date):
self.date = date
l = [Invoice(10), Payment(10), Invoice(10)]
def xcmp(x, y):
c0 = cmp(x.date, y.date)
return c0 if c0 != 0 else cmp(x.__class__.P, y.__class__.P)
l.sort(cmp=xcmp)