Django:在同一对多关系中使用多个联接的单个查询

时间:2017-10-17 20:25:12

标签: django django-orm

使用Django QuerySet API,如何在相同的两个表/模型之间执行多个连接?有关说明,请参阅以下未经测试的代码:

class DataPacket(models.Model):
    time = models.DateTimeField(auto_now_add=True)

class Field(models.Model):
    packet = models.ForeignKey(DataPacket, models.CASCADE)
    name = models.CharField(max_length=25)
    value = models.FloatField()

我想获取仅包含特定命名字段的数据包列表。我试过这样的事情:

pp = DataPacket.prefetch_related('field_set')
result = []
for p in pp:
    o = {
        f.name: f.value
        for f in p.field_set.all()
        if f.name in ('latitude', 'longitude')
    }
    o['time'] = p.time
    result.append(o)

但事实证明这是非常低效的,因为除了我想要的纬度和经度字段之外,我还在处理数百到数千个包含很多其他字段的数据包。

是否存在Django QuerySet调用,该调用转换为在不同行上执行从datapacket表到field表的两个内部联接的高效SQL查询?我可以使用原始SQL,如下所示(假设Django应用程序名为myapp)(同样,未经测试的代码用于说明目的):

from django.db import connection

with connection.cursor() as cursor:
    cursor.execute('''
        SELECT p.time AS time, f1.value AS lat, f2.value AS lon
        FROM myapp_datapacket AS p
        INNER JOIN myapp_field as f1 ON p.id = f1.packet_id
        INNER JOIN myapp_field as f2 ON p.id = f2.packet_id
        WHERE f1.name = 'latitude' AND f2.name = 'longitude'
    ''')
    result = list(cursor)

但本能告诉我如果不必这样做,就不要使用低级别的数据库API。支持这一点的可能原因可能是我的SQL代码可能与Django支持的所有DBM都不兼容,或者我觉得我更容易因误解SQL命令而破坏我的数据库而不是误解Django API打电话等。

1 个答案:

答案 0 :(得分:0)

在django中尝试Performing raw SQL queries。以及select related in raw request

原始查询的预取:

from django.db.models.query import prefetch_related_objects
raw_queryset = list(raw_queryset) 
prefetch_related_objects(raw_queryset, ['a_related_lookup',
'another_related_lookup', ...])

你的例子:

from django.db.models.query import prefetch_related_objects
raw_DataPacket = list(DataPacket.objects.raw)
pp = prefetch_related_objects(raw_DataPacket, ['field_set'])

使用Raw Queryset进行prefetch_related的示例:

模型:

class Country:
    name = CharField()
class City:
    country = models.ForeignKey(Country)
    name = models.CharField()

prefetch_related:

from django.db.models.query import prefetch_related_objects
#raw querysets do not have len()
#thats why we need to evaluate them to list
cities = list(City.objects.raw("select * from city inner join country on city.country_id = country.id where name = 'london'"))
prefetch_related_objects(cities, ['country'])

来自这些来源的信息提供的答案:djangoproject - performing raw queries | Related Stackoverflow Question | Google docs question