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)
Related
I have a model:
class Product(models.Model):
name = models.CharField(max_length=100)
class Sales(models.Model):
product_id = models.ForeignKey(Product, on_delete=models.CASCADE, related_name='products')
date = models.DateTimeField(null=True)
price = models.FloatField()
How do I return data as the following sql query (annotate sales with product name, group by product, day and month, and calculate sum of sales):
select p.name
, extract(day from date) as day
, extract(month from date) as month
, sum(s.price)
from timetracker.main_sales s
left join timetracker.main_product p on p.id = s.product_id_id
group by month, day, p.name;
Thanks,
If only ORM was as simple as sql... Spent several hours trying to figuring it out...
PS. Why when executing Sales.objects.raw(sql) with sql query above I get "Raw query must include the primary key"
You can annotate with:
from django.db.models import Sum
from django.db.models.functions import ExtractDay, ExtractMonth
Product.objects.values(
'name',
month=ExtractDay('products__date')
day=ExtractDay('products__date'),
).annotate(
total_price=Sum('products__price')
).order_by('name', 'month', 'day')
Note: Normally one does not add a suffix …_id to a ForeignKey field, since Django
will automatically add a "twin" field with an …_id suffix. Therefore it should
be product, instead of product_id.
Note: The related_name=… parameter [Django-doc]
is the name of the relation in reverse, so from the Product model to the Sales
model in this case. Therefore it (often) makes not much sense to name it the
same as the forward relation. You thus might want to consider renaming the products relation to sales.
I have a catalog and the price is a one to many relationship, so that I can track the price of a catalog item over time. The model looks like:
class CatalogItem(db.Model)
id = db.Column(db.Integer(), primary_key=True)
name = db.Column(db.String(250))
price = db.relationship("Price", back_populates="catalogitem")
class Price(db.Model):
id = db.Column(db.Integer(), primary_key=True)
price = db.Column(db.Float())
timestamp = db.Column(db.DateTime(), server_default=func.now(), nullable=False)
catalogitem_id = db.Column(db.Integer(), db.ForeignKey("catalogitem.id"))
catalogitem = db.relationship("CatalogItem", back_populates="material_einheitspreis_verkauf")
And this is my View. At least I managed to only show the price.
class CatalogItemView(ModelView):
inline_models = [(Price, dict(form_columns=["id","price"]))]
There are two issues:
When I render a catalog item and set price as inline model, I can do that just fine, but the default behavior would allow me to add multiple prices. What I would actually like to do is to have just a price field. I'm looking for a way to limit the form to just one entity (and also leaving away the button "add price".
When editing a catalogitem, it shouldn't edit the price, but actually create a new relationship -> basically when I edit the price it will create a new Price entity.
For 1 I have not idea on how to achieve this. For 2 I guess I could maybe do this by adding some kind of additional form field outside of the model and then create the "magic" with some kind of listeners.
Any other ideas?
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)
I got two models Article and Author implemented like this:
class Author(models.Model):
name = models.CharField(max_length=50)
class Article(models.Model):
name = models.CharField(max_length=50)
author = models.ForeignKey(Author, on_delete=models.CASCADE)
pub_date = models.DateField()
On my template I want to plot a graph (using chart.js on the frontend side) showing the authors publications per month, for the last 12 months. For that I need the count of articles published each month.
This is the query to get the authors articles:
articles = Article.objects.filter(author=author)
What would be best practice to get the count per month?
I've thought about annotating each of the twelve month separately to the QuerySet, but haven't found a way that works for me.
Alternatively, I thought about dealing with this on the JS site in the users browser.
Any suggestions/recommendations?
If you need to group data in Django you'll need to use ORM aggregation features.
And to use that on dates you can leverage their ORM helper functions.
from django.db.models.functions import TruncMonth
from django.db.models import Count
Article.objects
.filter(author=author) # Filter by the author
.annotate(month=TruncMonth('created')) # Truncate by month and add 'month' to values
.values('month') # Group By month
.annotate(count_id=Count('id')) # Count the number of articles in the grouping
.order_by('-month')[:12] # Sort by months in descending order (latest to earliest) and get the 12 first results
I'm trying to write a query in Django where I query a value from a table based on both the value of the foreign key and a modification to the foreign key. Consider an example database that stores the names, teams, and records of a team in one table that links to the league's revenue in another:
class League(models.Model):
id = models.PositiveSmallIntegerField(primary_key=True)
revenue = models.IntegerField(max_length=5)
class Team(models.Model):
name = models.TextField(max_length=20)
year = models.ForeignKey(League, max_length=4)
record = models.TextField(max_length=10)
How would I write a query so that I could create a table that included the name of the team, the year, this year's revenue, and the previous year's revenue?
You can define a many to many relationship:
class YearlyReport(models.Model):
year = models.CharField(max_length=4)
revenue = models.IntegerField(default=0)
class Team(models.Model):
name = models.CharField(max_length=20)
yearly_reports = models.ManyToManyField(YearlyReport)
And this is how you can add the reports:
t = Team(name='Test Team')
yearly_report_for_2018 = YearlyReport(revenue=100000, year='2018')
yearly_report_for_2017 = YearlyReport(revenue=50000, year='2017')
t.yearly_reports.add(yearly_report_for_2018)
t.yearly_reports.add(yearly_report_for_2017)
This is how you can get the reports:
r = YearlyReport.objects.get(team__name='Some Team')
print(r.year, r.revenue)
more in official docs here:
https://docs.djangoproject.com/en/2.0/topics/db/examples/many_to_many/