我有一个模特:
class Trades(models.Model):
userid = models.PositiveIntegerField(null=True, db_index=True)
positionid = models.PositiveIntegerField(db_index=True)
tradeid = models.PositiveIntegerField(db_index=True)
orderid = models.PositiveIntegerField(db_index=True)
...
我想执行下一个查询:
select *
from trades t1
inner join trades t2
ON t2.tradeid = t1.positionid and t1.tradeid = t2.positionid
可以在没有使用Django ORM的黑客的情况下完成吗? THX!
答案 0 :(得分:2)
选择* ... 将需要更多的工作。如果你可以从右侧修剪你想要的列
table=SomeModel._meta.db_table
join_column_1=SomeModel._meta.get_field('field1').column
join_column_2=SomeModel._meta.get_field('field2').column
join_queryset=SomeModel.objects.filter()
# Force evaluation of query
querystr=join_queryset.query.__str__()
# Add promote=True and nullable=True for left outer join
rh_alias=join_queryset.query.join((table,table,join_column_1,join_column_2))
# Add the second conditional and columns
join_queryset=join_queryset.extra(select=dict(rhs_col1='%s.%s' % (rhs,join_column_2)),
where=['%s.%s = %s.%s' % (table,join_column_2,rh_alias,join_column_1)])
添加其他列以供选择字典使用。
其他约束在ON()之后放在WHERE中,您的SQL引擎可能会很差地优化。
答案 1 :(得分:1)
我相信 Django的ORM不支持对未指定为ForeignKey的任何事情进行连接(至少,上次我调查它时,这是一个限制。他们是总是添加功能,所以也许它偷偷摸摸)。
因此,您可以选择重新构建表,以便使用正确的外键,或者只执行原始SQL查询。
我不认为原始SQL查询是“hack”。 Django在how to do raw SQL Queries上有很好的文档。
答案 2 :(得分:0)
在最新版本的Django中,您可以添加自联接。 Django版本2.11.7的示例。
示例代码。
Python 3.7.4 (default, Jul 9 2019, 18:14:44)
Type 'copyright', 'credits' or 'license' for more information
IPython 7.9.0 -- An enhanced Interactive Python. Type '?' for help.
In [1]: statistic = Statistic.objects.get(id=1)
In [2]: statistic.next.calculate_and_save_changed_from_previous_json()
In [3]:
depot_maestro / models / statistic.py的内容
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models
from .depot import Depot
class Statistic(models.Model):
id = models.IntegerField(primary_key=True,help_text='284.8',db_column='id',db_index=True)
previous = models.ForeignKey('self',null=True,help_text='284.29',db_column='previous_id',db_index=True,on_delete=models.SET_NULL,related_name='statistic_previous')
next = models.ForeignKey('self',null=True,help_text='284.30',db_column='next_id',db_index=True,on_delete=models.SET_NULL,related_name='statistic_next')
uuid = models.UUIDField(null=True,blank=True,help_text='284.1',db_column='uuid',db_index=True,unique=True)
change_from_previous_json = models.TextField(null=True,help_text='284.13',db_column='change_from_previous_json',db_index=True)
json = models.TextField(null=True,help_text='284.28',db_column='json',db_index=True)
constant = models.BooleanField(null=True,blank=True,help_text='284.11',db_column='constant',db_index=True,default=True)
deleted = models.BooleanField(null=True,blank=True,help_text='284.19',db_column='deleted',db_index=True)
included = models.BooleanField(null=True,blank=True,help_text='284.18',db_column='included',db_index=True)
creation_account = models.CharField(null=True,blank=True,max_length=128,help_text='284.3',db_column='creation_account',db_index=True)
creation_timestamp = models.DateTimeField(null=True,blank=True,help_text='284.4',db_column='creation_timestamp',db_index=True)
modification_account = models.CharField(null=True,blank=True,max_length=128,help_text='284.2',db_column='modification_account',db_index=True)
modification_timestamp = models.DateTimeField(null=True,blank=True,help_text='284.5',db_column='modification_timestamp',db_index=True)
filemaker_base_table_id = 284
def __str__(self):
return 'id: %d next: %d previous: %d' % (self.id, self.next_id, self.previous_id)
class Meta:
db_table = 'statistic'
managed = False
verbose_name = 'Statistic'
verbose_name_plural = 'StatisticList'
depot_maestro / models / init .py
的内容import json
from .statistic import Statistic
from .depot import Depot
from .owner import Owner
from .models import *
def statistic_calculate_and_save_changed_from_previous_json(self,verbose=False):
if verbose: print('calculate_and_save_changed_from_previous_json.started')
if self.previous:
if verbose: print('calculate_and_save_changed_from_previous_json.self.previous')
results = {}
previous = json.loads(self.previous.json)
now = json.loads(self.json)
for key in now:
if key in previous:
now_node = now[key]
previous_node = previous[key]
if 'count' in now_node and 'count' in previous_node:
results[key] = {}
results[key]['count'] = {}
results[key]['count']['difference'] = now_node['count'] - previous_node['count']
if verbose: print( results )
self.change_from_previous_json = json.dumps(results, sort_keys=True)
self.save()
else:
if verbose: print('No previous id:', self.previous_id)
if verbose: print('calculate_and_save_changed_from_previous_json.finished')
pass
Statistic.calculate_and_save_changed_from_previous_json = statistic_calculate_and_save_changed_from_previous_json