query to django model to find best company sale in the month - django

I have two django model one "company" and the other is "MonthlyReport" of the company
I want to find out which company sale in current month had more than 20% of previous month sale
class Company(models.Model):
name = models.CharField(max_length=50)
class MonthlyReport(models.Model):
company = models.ForeignKey(Company,on_delete=models.CASCADE)
sale = models.IntegerField()
date = models.DateField()
How can i figure out this issue to find a company that has more than 20% sales over the previous month

You can certainly do it using the ORM. You will need to combine Max (or SUM depending on your use case) with a Q() expression filter and annotate the percentage increase to the queryset before filtering it.
You could do it in a single piece of code, but I have split it out because getting the dates and the query expressions are quite long. I have also put the increase value in a separate variable, rather than hardcoding it.
from datetime import datetime, timedelta
from django.db.models import Max, Q
SALES_INCREASE = 1.2
# Get the start dates of this month and last month
this_month = datetime.now().date().replace(day=1)
last_month = (this_month - timedelta(days=15)).replace(day=1)
# Get the maximum sale this month
amount_this_month = Max('monthlyreport__sale',
filter=Q(monthlyreport__date__gte=this_month))
# Get the maximum sale last month, but before this month
amount_last_month = Max('monthlyreport__sale',
filter=Q(monthlyreport__date__gte=last_month) & \
Q(monthlyreport__date__lt=this_month))
Company.objects.annotate(
percentage_increase=amount_this_month/amount_last_month
).filter(percentage_increase__gte=SALES_INCREASE)
Edit - removed incorrect code addition

There is probably a way to do this using ORM, but I would just go with python way:
First add related name to MonthlyReport
class Company(models.Model):
name = models.CharField(max_length=50)
class MonthlyReport(models.Model):
company = models.ForeignKey(Company, related_name="monthly_reports", on_delete=models.CASCADE)
sale = models.IntegerField()
date = models.DateField()
Then
best_companies = []
companies = Company.objects.all()
for company in companies:
two_last_monthly_reports = company.monthly_reports.order_by("date")[:2]
previous_report = two_last_monthly_reports[0]
current_report = two_last_monthly_reports[1]
if current_report.sale / previous_report.sale > 1.2:
best_companies.append(company)

Related

query to django model to compare daily sale over previous day (compare two row of database model)

I have a django model that is "DailyReport" of the companies sale I want to find out company sale change over the previous day.
the model that i define is like that:
class DailyReport(models.Model):
company = models.CharField(max_length=50)
sale = models.IntegerField()
date = models.DateField()
How can i figure out this issue to add new column for every report that represent change rate over the previous day
Use the Lag window function to annotate each row with the previous sale amount for that company.
Then use another annotation to calculate the difference between the current and previous sale
from django.db.models import Window, F
from django.db.models.functions import Lag
DailyReport.objects.annotate(
prev_val=Window(
expression=Lag('sale', default=0),
partition_by=['company'],
order_by=F('date').asc(),
)
).annotate(
diff=F('sale') - F('prev_val')
)
Assuming you can have only one record of a company for each day, you can create a model property:
#property
def previous_day_sale(self):
date = self.date
dr = DailyReport.objects.filter(company=self.company, date=date-timedelta(days=1)
if dr:
return dr.first().sale - self.sale
You may need to override the save method, but you will have to cover all edge cases.
class DailyReport(models.Model):
company = models.CharField(max_length=50)
sale = models.IntegerField()
date = models.DateField()
sale_over_previous_day = models.IntegerField()
def save(self, *args, **kwargs):
previous_day_sale_object = DailyReport.objects.filter(company=self.company, date=date-timedelta(days=1))
if previous_day_sale_object:
previous_day_sale = previous_day_sale_object[0].sale
else:
previous_day_sale = 0
self.sale_over_previous_day = self.sale - previous_day_sale
super(DailyReport, self).save(*args, **kwargs)

Django ORM query on fk set

I have a problem with lookup that looks for a value in related set.
class Room(models.Model):
name = models.Charfield(max_lentgh=64)
class Availability(models.Model):
date = models.DateField()
closed = models.BooleanField(default=False)
room = models.ForeignKey(Room)
Considering that there is one availability for every date in a year. How can use ORM query to find whether room withing given daterange (i.e. 7 days) has:
availability exist for every day within given daterange
none of the availabilities has closed=True
I was unable to find any orm examples that check whether all objects within daterange exist
You can enumerate over the dates, and ensure that it has for that date an Availability with closed=False:
from datetime import date, timedelta
rooms = Room.objects.all()
start_date = date(2022, 7, 21) # first day
for dd in range(7): # number of days
dt = start_date + timedelta(days=dd)
rooms = rooms.filter(availability__date=dt, availability__closed=False)
The rooms will after the for loop have a QuerySet with all Rooms that have for all dates in that range Availability objects with closed=False.

how to filter by month from template

I'm attempting to channel a datetime field by month and year. Though no one can really say why while entering both month and year I get back a vacant set returned.
Model
class SpareParts(models.Model):
vehicle = models.ForeignKey(Vehicle, on_delete=models.CASCADE)
amount = models.IntegerField(blank=False, null=False)
date = models.DateField(blank=False, null=False)
And i want to filter on the basis of vehicle and month vise and here is mine view
VIEWS.py
def view_spare(request):
sparepart = SpareParts.objects.all()
vehicle_filter = request.POST.get('vehicle') # get the value of the date field
month_filter = request.POST.get('month') # get the value of the date field
if vehicle_filter:
if month_filter:
sparepart = sparepart.filter(vehicle=vehicle_filter,date__month=month_filter).aggregate(Sum('amount'))
return render(request,'invoice/spare_parts_list.html',{'sparepart':sparepart})
and i want render the whole month sum of amount in template
date__month is an integer and according to your explanation “month” is a date field. So, you cannot compare them. You have to calculate the month and the year of your date input:
Do this:
import datetime
month_filter = datetime.datetime.strptime(self.request.POST.get('month'),"%d/%m/%Y").date() #Change with the formar that you are using.
And:
sparepart = sparepart.filter(vehicle=vehicle_filter,date__month=month_filter.month, date__year=month_filter.year).aggregate(Sum('amount'))

Django Models for Time Series Data

My friends and I building an app that buy and sell stocks and we want to keep the historical prices of each stocks that we have in our possession by the end of day. The 3 most important fields are the ticker symbol and the price and the date.
For example:
01/01/2018 - Bought Stock A, record price of Stock A at end of day(EOD)
01/02/2018 - Did nothing, record price of Stock A at EOD
01/03/2018 - Bought Stock B, record price of Stock A and Stock B at EOD
01/04/2018 - Sell Stock A, record price of Stock B at EOD
We are using Django to build the models. Everyday we will record the price of each stock we have in our possession. This set of data is only for external use and will not be exposed to the public.
My initial research tells me it is not ideal to have a single table for historical prices and store each price for per stock as a single row. I'm not sure what the best approach is while using Django. What would the Django model to store all of this data look like and should we be using MYSQL?
You separate into 3 data models:
The model for the stock, having links to histories and current price and amount, as well as metadata
The model for the purchase history
The model for the price history
The three are linked with foreign keys from the stock model. Example code:
from django.db import models
from django.util.translation import ugettext_lazy as _
from datetime import date
class StockAsset(models.Model):
symbol = models.CharField(max_length=5)
amount = models.PositiveIntegerField()
price = models.FloatField()
class PurchaseHistory(models.Model):
BUY = 1
SELL = 2
ACTION_CHOICES = (
(BUY, _('buy')),
(SELL, _('sell')),
)
action = models.PositiveIntegerField(choices=ACTION_CHOICES)
action_date = models.DateTimeField(auto_now_add=True)
stock = models.ForeignKey(StockAsset,
on_delete=models.CASCADE, related_name='purchases'
)
class PriceHistory(models.Model):
stock = models.ForeignKey(StockAsset, on_delete=models.CASCADE, related_name='price_history')
price_date = models.DateField(default=date.today)
This way you can access all from the StockAsset model. Start reading here.
For this, the type of database to pick is not really important. If you have no preference, go with PostgreSQL.
If you care only about date, and not timestamp of every tick of price change
then django-simple-history is a way to go.
You just update value (a price) and saving it in time series in a different table is up to that library, not even need to define a date field.
class StockAsset(models.Model):
history = HistoricalRecords()
symbol = models.CharField(...)
price = models.DecimalField(max_digit=8, decimal_places=2)

How to filter latest objects using nested query in Django

I have the following relation:
class Product(foo):
name = models.CharField()
class Maintenance(foo):
product = models.ForeignKey(Product, related_name="maintenances")
start = models.DateField()
end = models.DateField()
I would like to filter all products with the latest (only the latest) maintenance object having start and end attributes in a given date range.
Something like this:
Product.objects.filter(maintenances__last__end__gte=today.now(), maintenances__last__end__lte=today.now()+datetime.timedelta(days=30))
You could filter the products on the selected range of dates for maintenances and then take the lastest maintenance using annotation on Max:
import datetime as dt
from django.db.models import Max
start_date = dt.datetime.now()
end_date = dt.datetime.now() + dt.timedelta(days=30)
products = Product.objects.filter(maintenances__start__gte=start_date, maintenances__end__lte=end_date)\
.annotate(most_recent_maint=Max('maintenances__id'))\
.prefetch_related('maintenances')
In some cases it also might make sense to think the other way round: Select the latest Maintenance object for every product:
# filter for time range
maintenances = Maintenance.objects.filter(
end__gte=today.now(),
end__lte=today.now() + datetime.timedelta(days=30)
)
# get latest with distinct product id
maintenances = maintenances.order_by(
'product_id', '-end'
).distinct('product_id')
# do a `select_related` to get all products in the same query
maintenances = maintenances.select_related('product')
Note that passing arguments to distinct() only works if you are using PostgreSQL.