自我加入django ORM

时间:2009-10-16 14:21:51

标签: django

我有一个模特:

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!

3 个答案:

答案 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