Django queryset for current year - django

I have my query written to get some thing from database and display on my website that query is getting all the data from db but what if i want to get the data particular to current year only
def get(self, request, *args, **kwargs):
filters = self.get_filters()
result = Model.objects.all().filter(*filters).distinct().aggregate(
t=Sum('t'),
b=Sum('b'),
)
result2 = Model.objects.all().filter(*filters).distinct().aggregate(
past_due=Sum('balance', filter=Q(due_date__lt=timezone.now()))
)
zero = Decimal('0.00')
total = result['t'] or zero
balance = result['b'] or zero
past_due = result2['past_due'] or zero
amount_received = t - b

I think filter=Q(due_date__year=datetime.now().date().year) should work for you, if I understand your question correctly.

This worked for me
result = Model.objects.all().filter(*filters, created__year=datetime.now().year).distinct().aggregate(
t=Sum('t'),
b=Sum('b'),
)
result2 = Model.objects.all().filter(*filters, created__year=datetime.now().year).distinct().aggregate(
past_due=Sum('balance', filter=Q(due_date__lt=timezone.now()))
)

Related

Django validation of number from query string

Im having this code to create and add students to database.
I need to make validation of count which must be integer, only positive, equal or less 100.
Please help.
def generate_students(request):
count = request.GET.get('count')
studentslist = []
for student in range(0, int(count)):
student = Student.objects.create(first_name = fake.first_name(), last_name = fake.last_name(), age = random.randint(18,100))
studentslist.append(student)
output = ', '.join(
[f"id = {student.id} {student.first_name} {student.last_name}, age = {student.age};" for student in studentslist]
)
return HttpResponse(str(output))
The best way is likely to work with a form, since a form has a lot of validation inplace, can clean the object, and print sensical errors.
We thus can work with a simple form:
from django import forms
class CountForm(forms.Form):
count = forms.IntegerField(min_value=1, max_value=100)
then we can validate the input with:
def generate_students(request):
form = CountForm(request.GET)
if form.is_valid():
count = form.cleaned_data['count']
studentslist = [
Student.objects.create(first_name = fake.first_name(), last_name = fake.last_name(), age = random.randint(18,100))
for _ in range(count)
]
output = ', '.join(
[f'id = {student.id} {student.first_name} {student.last_name}, age = {student.age};'
for student in studentslist]
)
else:
return HttpResponse(str(form.errors))
return HttpResponse(str(output))
Note: Section 9 of the HTTP protocol
specifies that requests like GET and HEAD should not have side-effects, so you
should not change entities with such requests. Normally POST, PUT, PATCH, and
DELETE requests are used for this. In that case you make a small <form> that
will trigger a POST request, or you use some AJAX calls.

Django: How to take my query out of my for loop

I got the following code, that contains N queries:
for qty in total_qty_bought:
product_id = qty["product"]
quantity = int(qty["quantity__sum"])
try:
method_title = (
self.shipment_model.get(order_id=qty["order_id"])
.method_title.replace("Hent-selv", "")
.strip()
)
To solve the issue I tried to take the method_title query out of the for loop like this:
quantity = 0
for qty in total_qty_bought:
quantity = int(qty["quantity__sum"])
method_title = (
self.shipment_model.get(order_id=total_qty_bought[0]['order_id'])
.method_title.replace("Hent-selv", "")
.strip()
)
Note! There will be a full refrence further down, to understand the bigger picture
The issue in my solution is, that I am hard choosing which dict to enter , as I select [0] before order_id, and not in a for loop like before, would be selecting every individual item in the loop.
Is there a more sufficient way to do this? I do not see a solution without the for loop, but django debugger tool tells me it creates 2k+ queries.
CODE FOR REFRENCE
class InventoryStatusView(LoginRequiredMixin, View):
template_name = "lager-status.html"
cinnamon_form = CinnamonForm(prefix="cinnamon_form")
peber_form = PeberForm(prefix="peber_form")
pc_model = InventoryStatus
product_model = Product.objects.all()
order_item_model = WCOrderItem.objects.all()
shipment_model = WCOrderShipment.objects.all()
def get(self, request):
# Get all added objects that hasn't been deleted
objects = self.pc_model.objects.filter(is_deleted=False)
# Get all added objects that has been deleted
deleted_objects = self.pc_model.objects.filter(is_deleted=True)
# Sum all cinnamon that isn't deleted
total_cinnamon = (
self.pc_model.objects.filter(is_deleted=False)
.aggregate(Sum("cinnamon"))
.get("cinnamon__sum", 0.00)
)
# Sum all peber that isn't deleted
total_peber = (
self.pc_model.objects.filter(is_deleted=False)
.aggregate(Sum("peber"))
.get("peber__sum", 0.00)
)
# Get the amount of kilo attached to products
product_data = {}
queryset = ProductSpy.objects.select_related('product')
for productSpy in queryset:
product_data[productSpy.product.product_id] = productSpy.kilo
# Get quantity bought of each product
total_qty_bought = self.order_item_model.values(
"order_id", "product"
).annotate(Sum("quantity"))
# Get the cities from the inventory model
cities = dict(self.pc_model.CITIES)
# Set our total dict for later reference
our_total = {}
product = Product.objects.filter(
product_id__in={qty['product'] for qty in total_qty_bought}
).first()
# Check if we deal with kanel or peber as a product based on slug
index = 0
if product.slug.startswith("kanel-"):
index = 0
elif product.slug.startswith("peber-"):
index = 1
else:
pass
try:
# Sum the total quantity bought
quantity = 0
for qty in total_qty_bought:
quantity = int(qty["quantity__sum"])
# Get the inventory the order is picked from based on shipment method title
method_title = (
self.shipment_model.get(order_id=total_qty_bought[0]['order_id']) # The error
.method_title.replace("Hent-selv", "")
.strip()
)
# If the order isn't picked, but sent, use this inventory
if method_title not in cities.values():
method_title = "Hovedlager"
try:
# Get the total of kanel and peber bought
kilos = quantity * product_data[product.id]
# If there is no inventory, set it to 0 peber and 0 kanel
if method_title not in our_total:
our_total[method_title] = [0, 0]
# Combine place and kilos
our_total[method_title][index] += kilos
except KeyError as ex:
print(ex)
pass
except WCOrderShipment.DoesNotExist as ed:
print(ed)
pass
# Quantities BOUGHT! (in orders!)
print(our_total)
context = {
"cinnamon_form": self.cinnamon_form,
"peber_form": self.peber_form,
"objects": objects,
"deleted_objects": deleted_objects,
"total_cinnamon": total_cinnamon,
"total_peber": total_peber,
"our_total": our_total,
}
return render(request, self.template_name, context)
You can only do one query by using the __in operator:
shipments = self.shipment_model.get(order_id__in=list_containing_order_ids)
Then you can do a normal for loop in which you verify that condition.

django filter queryset show variables on template [duplicate]

This question already has an answer here:
Django-Filter Package: How To Filter Objects To Create Stats And Not Lists
(1 answer)
Closed 2 years ago.
Below is the views.py to my stats page. This page has a bunch of calculations based on my model objects. Works great. However when I apply django-filter to the data it does not change. Example filtering for only "short" trades or in the "last 7 days".
I know that get_context_data is basically hardcoding the results and it will not be affected by any filter query. This is not the approach but I've tried several things with no results so back to square one... How would I do this?
I've tried kwargs.update and context.update but also was not getting results.
This seems like it should be super obvious as how else do people show and filter statistics on objects?
views.py
class StatsView(LoginRequiredMixin, FilterView):
model = Trade
template_name = 'dashboard/stats.html'
filterset_class = StatsFilter
def get_form(self, *args, **kwargs):
form = StatsFilter()
user = self.request.user
form.fields['associated_portfolios'].queryset = Portfolio.objects.filter(user=user)
return form
def get_max_consecutive_wins(self, data):
longest = 0
current = 0
for num in data:
if num > 0:
current += 1
else:
longest = max(longest, current)
current = 0
return max(longest, current)
def get_max_consecutive_loses(self, data):
longest = 0
current = 0
for num in data:
if num < 0:
current += 1
else:
longest = max(longest, current)
current = 0
return max(longest, current)
def get_context_data(self, *args, **kwargs):
trade = Trade.objects.filter(user=self.request.user, status='cl').order_by('created')
all_trades = Trade.objects.filter(user=self.request.user, status='cl').count()
context = super(StatsView, self).get_context_data(*args, **kwargs)
data = [t.profit_loss_value_fees for t in trade]
win_trades_count = [t.trade_result for t in trade].count('win')
loss_trades_count = [t.trade_result for t in trade].count('loss')
scratch_trades_count = [t.trade_result for t in trade].count('scratch')
avg_win = 0 if win_trades_count == 0 else mean(t.profit_loss_value_fees for t in trade if t.trade_result == 'win')
avg_loss = 0 if loss_trades_count == 0 else mean(t.profit_loss_percent for t in trade if t.trade_result == 'win')
avg_win_percent = 0 if win_trades_count == 0 else mean(t.profit_loss_percent for t in trade if t.trade_result == 'win')
avg_loss_percent = 0 if loss_trades_count == 0 else mean(t.profit_loss_percent for t in trade if t.trade_result == 'loss')
context['all_trades'] = all_trades
context['gross_profit'] = sum([t.profit_loss_value for t in trade])
context['net_profit'] = sum([t.profit_loss_value_fees for t in trade])
context['win_trades_profit'] = sum(
t.profit_loss_value_fees for t in trade if t.trade_result == 'win')
context['loss_trades_profit'] = sum(
t.profit_loss_value_fees for t in trade if t.trade_result == 'loss')
context['win_trades_count'] = win_trades_count
context['loss_trades_count'] = loss_trades_count
context['scratch_trades_count'] = scratch_trades_count
context['win_trades_count_ratio'] = win_trades_count / all_trades * 100
context['loss_trades_count_ratio'] = loss_trades_count / all_trades * 100
context['scratch_trades_count_ratio'] = scratch_trades_count / all_trades * 100
context['total_fees'] = sum([t.get_fees() for t in trade])
context['avg_win'] = avg_win
context['avg_loss'] = avg_loss
context['avg_win_percent'] = avg_win_percent
context['avg_loss_percent'] = avg_loss_percent
context['avg_position_size'] = mean(t.position_size for t in trade)
context['largest_winning_trade'] = max([t.profit_loss_value_fees for t in trade])
context['largest_losing_trade'] = min([t.profit_loss_value_fees for t in trade])
context['largest_winning_trade_percent'] = max([t.profit_loss_percent for t in trade])
context['largest_losing_trade_percent'] = min([t.profit_loss_percent for t in trade])
context['max_consecutive_wins'] = self.get_max_consecutive_wins(data)
context['max_consecutive_loses'] = self.get_max_consecutive_loses(data)
context['qs'] = Trade.objects.filter(user=self.request.user, status='cl').order_by('created')
return context
The first problem, like you pointed, is that you are hard-coding the results in the get_context_data(). The FilterView ClassBasedView inherits from the MultipleObjectsMixin mixin of Django, so you should take both into account. I assume from your issues that you are not using the object_list property in your template - that's where the CBV populates the data.
Basically, in your current view, the flow will go as:
get the queryset based in the get_queryset() method.
If this doesn't exist, it will use the queryset property defined
In last case, the model. <-- This is your case, so it will use Trade.objects.all()
the FilterSet is applied to the original queryset
paginate (if you have it configured) and assign the filtered queryset to the object_list in the context.
So, some changes you can start trying:
Use the object_list to perform the stats calculation in your get_context_data() instead of querying for the Trade model yourself.
If you are always going to filter the results based in the current user, you can use the get_queryset() method to apply that filter from there, so you would do:
def get_queryset(self):
qs = super().get_queryset()
return qs.filter(user=self.request.user, status='cl')
I would also recommend you to look at Django's built-in data aggregation mechanisms, as it would make all those calculations at DB level. If your start to treat big amounts of data, making all this manual processing is going to be an issue.
I think those points would be a good start!

Django querysets to subtract items

I have two query sets to get the values for stock_in and stock_out. How do i loop to subtract stock_out from stock_in
here are the querysets
stock_in = OrderItems.objects.values('drug').annotate(
quantity_received=Sum('quantity_received'),
).order_by('drug')
stock_out = RequestItems.objects.values('drug').annotate(
quantity_received=Sum('quantity_issued')
).order_by('drug')
Approach it from the Drug model. It makes it a bit easier on the query.
Drug.objects.annotate(
stock_in=Sum('orderitems_set__quantity_received'),
stock_out=Sum('requestitems_set__quantity_issued'),
).annotate(
current_stock=F('stock_in')-F('stock_out')
)
Or you might be able to do it in one. I'm not sure.
Drug.objects.annotate(
current_stock=Sum('orderitems_set__quantity_received') - Sum('requestitems_set__quantity_issued'),
)
def stock_list(request):
stock_in = OrderItems.objects.values('drug__drugTitle','drug__drugCode', 'drug__denom_quantity').order_by('drug').annotate(quant_in=Sum('quantity_received'))
stock_out = RequestItems.objects.values('drug__drugTitle', 'drug__drugCode', 'drug__denom_quantity').order_by('drug').annotate(quant_out=Sum('quantity_issued'))
stock_available=[]
index = 0
for item in stock_out:
if item is None:
remaining_stc = stock_in[index]['quant_in']
stock_available.append({'drug__drugTitle':stock_in[index]['drug__drugTitle'],'drug__drugCode':stock_in[index]['drug__drugCode'], 'drug__denom_quantity':stock_in[index]['drug__denom_quantity'], 'quantr':remaining_stc})
else:
remaining_stc = stock_in[index]['quant_in']-stock_out[index]['quant_out']
stock_available.append({'drug__drugTitle':stock_in[index]['drug__drugTitle'],'drug__drugCode':stock_in[index]['drug__drugCode'], 'drug__denom_quantity':stock_in[index]['drug__denom_quantity'], 'quantr':remaining_stc})
index = index + 1
context = {
"stock_available":stock_available,
}
return render(request, 'stock/stock_list.html', context)

For loop in Django

I have two question. First question: Python script that shows me the precipitation for a certain period.For example, I'm getting an initial year-month and a final year-month.
Initial:
year:2000
month:3
Final
year1:2005
month:4
Now, instead of seeing:
2000/3,2000/4,2000/5,2000/6..........2005/1,2005/2,2005/3,2005/4
she works like this(look in the hooked picture):
2000/3, 2000/4, 2001/3, 2001/4........2005/3,2005/4.
I want to work for me like the first case.
def period_month_prec(year,month,year1,month1):
for i in range (year,year1+1,1):
for j in range(month,month1+1,1):
......................
Second question: How to write the output(picture) from the script in csv.fileenter image description here
This is what my views.py script looks like , which saves me only the first result:
def monthly_period(request):
if request.method == "POST" :
form = PeriodMonthlyForm(request.POST)
if form.is_valid():
data = form.cleaned_data
year = data.get('year')
month = data.get('month')
year1 = data.get('year1')
month1 = data.get('month1')
lon = data.get('lon')
lat = data.get ('lat')
inter = data.get('inter')
point = period_month_prec(year,month,year1,month1,lon,lat)
args = {'point':point}
response = HttpResponse(content_type='text/txt')
response['Content-Disposition'] = 'attachment; filename="precipitation.txt"'
writer = csv.writer(response)
writer.writerow([point])
return response
else:
form = PeriodMonthlyForm()
active_period_monthly = True
return render (request, 'carpatclimapp/home.html',{'form':form, 'active_period_monthly': active_period_monthly})
Ok, i have forms like this:
Forms
You set initial values(red color) and end interval(blue color). For this given interval, the lon and lat are defined for the point in which we want to perform interpolation. When you press the submit button, it starts with interpolation for a defined period. The loop problem is because it works only for the defined months (we see from the 2nd picture that it only works in the interval 1-6) but not for 7,8,9,10,11,12 months between these years.
Initial: year:2000, month:3
Final: year1:2001, month:4
for this she's doing it like this: 2000/3,2000/4,2001/3,2001/4
I do not want that, I want this: 2000/3,2000/4,2000/5,2000/6,2000/7.....2000/12,2001/1,2001/2,2001/3,2001/4.
this is me code :
def period_month_prec(year,month,year1,month1,lon,lat):
cnx = sqlite3.connect(DB1)
cursor = cnx.cursor()
table = 'monthly'
year = int(year)
year1 = int(year1)
month = int(month)
month1 = int(month1)
for i in range (year,year1+1,1):
for j in range(month,month1+1,1):
query = '''
SELECT dates, cell, prec FROM %s WHERE dates = "%s-%s" ;
''' % (table,i,j)
df = pd.read_sql_query(query, cnx)
tacka = '''SELECT id, lon, lat,country,altitude FROM %s;''' % 'grid1'
grid1 = pd.read_sql_query(tacka, cnx)
podaci = pd.merge(df,grid1,left_on='cell',right_on='id')
podaci_a = podaci.drop(['cell','id','country','altitude'],axis=1)
lon_n = podaci_a['lon'].values
lat_n = podaci_a['lat'].values
prec =podaci_a['prec'].values
x_masked, y_masked, prec_p = remove_nan_observations(lon_n, lat_n, prec)
xy = np.vstack([x_masked,y_masked]).T
xi = ([lon,lat])
inter_point = interpolate_to_points(xy,prec_p,xi, interp_type='linear'
return (i,j,lon,lat,inter_point)
The results that come out look like this:
loop with calculations
The second question was how to save these results(2nd picture) in the csv file, how to write correctly views.py. Currently she looks like this :
def monthly_period(request):
if request.method == "POST" :
form = PeriodMonthlyForm(request.POST)
if form.is_valid():
data = form.cleaned_data
year = data.get('year')
month = data.get('month')
year1 = data.get('year1')
month1 = data.get('month1')
lon = data.get('lon')
lat = data.get ('lat')
inter = data.get('inter')
point = period_month_prec(year,month,year1,month1,lon,lat)
args = {'point':point}
response = HttpResponse(content_type='text/txt')
response['Content-Disposition'] = 'attachment; filename="precipitation.txt"'
writer = csv.writer(response)
writer.writerow([point])
return response
else:
form = PeriodMonthlyForm()
active_period_monthly = True
return render (request, 'carpatclimapp/home.html',{'form':form, 'active_period_monthly': active_period_monthly})
I hope I'm a little clearer now