Annotated value gives None, need 0 - python

order_list_cases =(order_list.values('user_id').annotate(dcount=Count('user_id'),customer_paid_sum=(Sum('invoice__transaction_invoice__transaction_amount'))
In this code, the customer_paid_sumis returning None, I want to give it as 0 if it is None. I tried else case along with it but didn't work.

You can work with Coalesce [Django-doc] to return 0 instead of None if the aggregate works over an empty collection:
from django.db.models import Value
from django.db.models.functions import Coalesce
order_list_cases = order_list.values('user_id').annotate(
dcount=Count('user_id'),
customer_paid_sum=Coalesce(
Sum('invoice__transaction_invoice__transaction_amount'),
Value(0)
)
)

Related

Don't use empty/none variables in method/class

I have a class that looks something like:
#dataclass
class MyClass:
df1: pd.Series = None
df2: pd.Series = None
df3: pd.Series = None
df4: pd.Series = None
df5: pd.Series = None
#property
def series_mean(self) -> pd.Series:
series_mean = (
self.df1
+ self.df2
+ self.df3
+ self.df4
+ self.df5
).mean()
return series_mean
Generally this could just be done as a function alone, but for this case, let's just assume I do this.
Now, my issue now is, that none of the df's are mandatory, so I could just give it df1 and df5. In that case, the mean doesn't work due to the None in the class.
So how do I go about just using the ones that are not None ? And on top of that, is there a way to get how many of them are not None? I mean, if I wanted to do / 2 instead of .mean() if there is two that are not None.
Put them in a tuple instead and filter on None. Then you can easily both sum and and query len from the filtered tuple.
from typing import Tuple
#dataclass
class MyClass:
dfs: Tuple[pd.Series, pd.Series, pd.Series, pd.Series, pd.Series] = (None, None, None, None, None)
#property
def series_mean(self) -> pd.Series:
not_none = tuple(filter(None, self.dfs))
return sum(not_none) / len(not_none)
Assuming you actually need to keep this as five separate variables, which I doubt, you can use sum with a generator expression to filter out the none values
#property
def series_mean(self) -> pd.Series:
return sum(
df for df in
[self.df1, self.df2, self.df3, self.df4, self.df5]
if df is not None).mean

For filtering data in Django, build dynamic query for multiple columns

I have to filter data from model based on the run time values. I am getting 5 values via query string. My querystring is like below:
http://127.0.0.1:8000/personal/search/?month=&year=&account=&deliveryManagedFrom=&marketmName=
So, I want to include all or none of the values in the filter so that it displays the desired result. Below is the filter query which I am writing:
sum_tt_count = NetworkRelatedInformation.objects.filter(month=month, year=year, account_id=account, account__deliveryManagedFrom=deliveryManagedFrom, account__marketName=market).aggregate(Sum('tt_count'))
totalttcount = sum_tt_count['tt_count__sum']
It is working well in case, all the values have been provided.
In case, if any value is blank, it should not consider that value and display output as per other filter criteria.
Pls suggest how to implement an OR filter with 5 data inputs. It is not necessary that all 5 data inputs have values . So the value can be None or the value in the querystring
Filter the request for non-empty values and then use dictionary expansion to do the query.
q = {k:v for k, v in request.GET.items() if v}
sum_tt_count = NetworkRelatedInformation.objects.filter(**q).aggregate(Sum('tt_count'))
You can do it using Q object
from django.db.models import Q
NetworkRelatedInformation.objects.filter(Q(month__isnull=True) | Q(month=month), Q(year__isnull=True) | Q(year=year)).aggregate(Sum('tt_count'))
For handling the None values i have to explicitly write the below code.
account = request.GET.get('account')
if account is '':
account = None
month = request.GET.get('month')
if month is '':
month = None
year = request.GET.get('year')
if year is '':
year = None
sum_alarm_count = NetworkRelatedInformation.objects.filter(Q(month=month) | Q(year=year) | Q(account_id=account)) \
.aggregate(Sum('alarm_count'))
totalalarmcount = sum_alarm_count['alarm_count__sum']

Django - Iterate over queryset and add static values

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.

How to exclude fields when using Django _meta.get_fields()

My model has the standard "id" field, and I would like to exclude it when I use _meta.get_fields(). My current solution looks something like this:
context_var = (MyModel._meta.get_fields())[1:]
It works well enough, but I don't really like the slice solution. I'd rather remove the id field by name, or use a method that explicitly excludes the id field. Is there a more elegant solution?
You can do this:
context_var = [f for f in MyModel._meta.get_fields() if f.name != 'id']
Alternatively, you can use Python's built-in filter() function:
In [1]: context_var = filter(lambda x: x.name != 'id', MyModel._meta.fields)
In [2]: type(context_var)
Out[2]: filter
In [3]: for item in context_var: print(item)
MyModel.field1
MyModel.field2
...
The resulting value is of type filter which you can iter through, but, depending on what you need to do with context_var later, you might want to convert it into a tuple:
In [4]: context_var = tuple(filter(lambda x: x.name != 'id', MyModel._meta.fields))

sqlalchemy func.sum() returns None when no rows exist

I've managed to get a query working that sums up all the child rows of the parent class:
subq = db.session.query(Transaction.budget_id, func.sum(Transaction.amount).label("total"), func.count('*').label("count"))
.group_by(Transaction.budget_id).subquery()
return db.session.query(Budget.ID, Budget.name, Budget.start_date, Budget.end_date, Budget.amount, subq.c.total, subq.c.count)
.outerjoin(subq, Budget.ID==subq.c.budget_id)
.order_by(Budget.start_date.desc()).limit(count)
The problem is that it doesn't work when Budget doesn't have any Transaction subclasses. It returns None, which throws a spanner in the works. I want the sum() and count() functions to return 0 instead.
from sqlalchemy.sql.functions import coalesce
...
return db.session.query(Budget.ID,
Budget.name,
Budget.start_date,
Budget.end_date,
Budget.amount,
coalesce(subq.c.total, 0),
coalesce(subq.c.count, 0))
.outerjoin(subq, Budget.ID==subq.c.budget_id)
.order_by(Budget.start_date.desc()).limit(count)
2022 Answer
I want the sum() and count() functions to return 0 instead.
Based on the answer of #antonio_antuan but with sqlalchemy-1.4, now you can:
from sqlalchemy import func, select
stmt = select(func.coalesce(func.sum(Transaction.amount), 0))
s = db.session.execute(stmt).scalars().one()
and likewise for func.count.

Categories

Resources