Python 如何将此SQL语句转换为Django QuerySet?
请注意:这个问题是我几天前提出的后续问题。 它不是复制品。我试图在Django中建模的SQL查询与我加载的虚拟数据之间存在细微但显著的差异 我正在编写一个Python/Django应用程序来进行股票分析 我有两个非常简单的模型,如下所示:Python 如何将此SQL语句转换为Django QuerySet?,python,mysql,django,Python,Mysql,Django,请注意:这个问题是我几天前提出的后续问题。 它不是复制品。我试图在Django中建模的SQL查询与我加载的虚拟数据之间存在细微但显著的差异 我正在编写一个Python/Django应用程序来进行股票分析 我有两个非常简单的模型,如下所示: class Stock(models.Model): symbol = models.CharField(db_index=True, max_length=5, null=False, editable=False, unique=True) cl
class Stock(models.Model):
symbol = models.CharField(db_index=True, max_length=5, null=False, editable=False, unique=True)
class StockHistory(models.Model):
stock = models.ForeignKey(Stock, related_name='StockHistory_stock', editable=False)
trading_date = models.DateField(db_index=True, null=False, editable=False)
close = models.DecimalField(max_digits=12, db_index=True, decimal_places=5, null=False, editable=False)
class Meta:
unique_together = ('stock', 'trading_date')
这是我填充的虚拟数据:
import datetime
a = Stock.objects.create(symbol='A')
b = Stock.objects.create(symbol='B')
c = Stock.objects.create(symbol='C')
d = Stock.objects.create(symbol='D')
StockHistory.objects.create(trading_date=datetime.date(2018,1,1), close=200, stock=a)
StockHistory.objects.create(trading_date=datetime.date(2018,1,2), close=150, stock=a)
StockHistory.objects.create(trading_date=datetime.date(2018,1,3), close=120, stock=a)
StockHistory.objects.create(trading_date=datetime.date(2018,4,28), close=105, stock=a)
StockHistory.objects.create(trading_date=datetime.date(2018,5,2), close=105, stock=a)
StockHistory.objects.create(trading_date=datetime.date(2018,5,3), close=105, stock=a)
StockHistory.objects.create(trading_date=datetime.date(2017,5,2), close=400, stock=b)
StockHistory.objects.create(trading_date=datetime.date(2017,11,11), close=200, stock=b)
StockHistory.objects.create(trading_date=datetime.date(2017,11,12), close=300, stock=b)
StockHistory.objects.create(trading_date=datetime.date(2017,11,13), close=400, stock=b)
StockHistory.objects.create(trading_date=datetime.date(2017,11,14), close=500, stock=b)
StockHistory.objects.create(trading_date=datetime.date(2018,4,28), close=105, stock=c)
StockHistory.objects.create(trading_date=datetime.date(2018,4,29), close=106, stock=c)
StockHistory.objects.create(trading_date=datetime.date(2018,4,30), close=107, stock=c)
StockHistory.objects.create(trading_date=datetime.date(2018,5,1), close=108, stock=c)
StockHistory.objects.create(trading_date=datetime.date(2018,5,2), close=109, stock=c)
StockHistory.objects.create(trading_date=datetime.date(2018,5,3), close=110, stock=c)
StockHistory.objects.create(trading_date=datetime.date(2018,5,4), close=90, stock=c)
我想找出所有在过去一周内创下年度低点的股票
但为了让这个问题更简单,假设我想找到自'2017-05-04'
以来最低点出现在'2018-04-30'
当天或之后的所有股票。下面是我为查找它而编写的SQL。它起作用了
但是,我需要帮助确定要编写什么Django查询才能获得与此SQL相同的结果。我怎么做?在回答我之前的问题时,Django提供了3行结果,而不是2行
select
s.symbol,
min(sh.trading_date),
low_table.low
from
(
select
stock_id,
min(close) as low
from
stocks_stockhistory
where
trading_date >= '2017-05-04'
group by
stock_id
) as low_table,
stocks_stockhistory as sh,
stocks_stock as s
where
sh.stock_id = low_table.stock_id
and sh.stock_id = s.id
and sh.close = low_table.low
and sh.trading_date >= '2018-04-30'
group by
s.symbol,
low_table.low
order by
s.symbol asc;
+--------+----------------------+--------------------+
| symbol | min(sh.trading_date) | min(low_table.low) |
+--------+----------------------+--------------------+
| A | 2018-05-02 | 105.00000 |
| C | 2018-05-04 | 90.00000 |
+--------+----------------------+--------------------+
2 rows in set (0.01 sec)
你能试试吗
from stocks.models import StockHistory, Stock
from django.db.models import OuterRef, Subquery, F, Min
low = StockHistory.objects.filter(
stock=OuterRef('stock'), trading_date__gt='2017-05-04'
).order_by('close')
qs = StockHistory.objects.annotate(
low=Subquery(low.values('close')[:1])
)
qs = qs.filter(low=F('close')).filter(trading_date__gte='2018-04-30')
qs = qs.values('stock__symbol', 'low').order_by('stock__symbol', 'low')
qs = qs.annotate(mtd=Min('trading_date'))
qs = qs.values_list('stock__symbol', 'mtd', 'low')
qs = qs.order_by('stock__symbol', 'low')
结果是:
>>> qs
<QuerySet [('A', datetime.date(2018, 5, 2), Decimal('105.00000')), ('C', datetime.date(2018, 5, 4), Decimal('90.00000'))]>
如果您完全按照链接答案中提供的方式使用查询,则不应得到3行。您是否忘记了查询中的任何筛选器?仔细看一看。您可以在这里非常清楚地看到:是的,您在上一次查询中缺少了
过滤器中的交易日期
参数。很抱歉问这个问题。。。如果您可以用SQL来实现,那么为什么还要使用Django呢?我想知道Django在这种情况下给表带来了什么。老实说,我想在这种情况下使用原始sql。django orm在可读代码和查询效率方面没有提供任何帮助。我的结果与您的不同。看一看:@SaqibAli很抱歉我的第一个版本我没有疏忽,并根据您的第一个问题创建数据
>>> print(qs.query)
SELECT "stocks_stock"."symbol",
(SELECT U0."close"
FROM "stocks_stockhistory" U0
WHERE (U0."stock_id" = ("stocks_stockhistory"."stock_id")
AND U0."trading_date" > 2017-05-04)
ORDER BY U0."close" ASC LIMIT 1) AS "low",
MIN("stocks_stockhistory"."trading_date") AS "mtd"
FROM "stocks_stockhistory"
INNER JOIN "stocks_stock"
ON ("stocks_stockhistory"."stock_id" = "stocks_stock"."id")
WHERE (
(SELECT U0."close"
FROM "stocks_stockhistory" U0
WHERE (U0."stock_id" = ("stocks_stockhistory"."stock_id") AND U0."trading_date" > 2017-05-04)
ORDER BY U0."close" ASC LIMIT 1) = ("stocks_stockhistory"."close")
AND "stocks_stockhistory"."trading_date" >= 2018-04-30)
GROUP BY "stocks_stock"."symbol",
(SELECT U0."close"
FROM "stocks_stockhistory" U0
WHERE (U0."stock_id" = ("stocks_stockhistory"."stock_id") AND U0."trading_date" > 2017-05-04)
ORDER BY U0."close" ASC LIMIT 1)
ORDER BY "stocks_stock"."symbol" ASC, "low" ASC