2009-05-31 9 views
3

Ich habe ein Modell, „Markt“, die eine Eins-zu-viele-Beziehung zu einem anderen Modell hat, „Vertrag“:holen einreihiges Kind basierend auf einem Maximalwert mit Django ORM

class Market(models.Model): 
    name = ... 
    ... 

class Contract(models.Model): 
    name= ... 
    market = models.ForeignKey(Market, ...) 
    current_price = ... 

Ich würde gerne Market-Objekte zusammen mit dem Vertrag mit dem maximalen Preis von jedem zu holen. Dies ist, wie ich es über rohen SQL tun würde:

SELECT M.id as market_id, M.name as market_name, C.name as contract_name, C.price 
as price from pm_core_market M INNER JOIN 
    (SELECT market_id, id, name, MAX(current_price) as price 
     FROM pm_core_contract GROUP BY market_id) AS C 
ON M.id = C.market_id 

Gibt es eine Möglichkeit, diese SQL ohne zu implementieren? Wenn es welche gibt, welche sollte man in Bezug auf die Leistung bevorzugen?

Antwort

9

Django 1.1 (derzeit Beta) fügt der Datenbank-API aggregation Unterstützung hinzu. Ihre Anfrage kann wie folgt geschehen:

from django.db.models import Max, F 

Contract.objects.annotate(max_price=Max('market__contract__current_price')).filter(current_price=F('max_price')).select_related() 

Dies erzeugt die folgende SQL-Abfrage:

SELECT contract.id, contract.name, contract.market_id, contract.current_price, MAX(T3.current_price) AS max_price, market.id, market.name 
FROM contract LEFT OUTER JOIN market ON (contract.market_id = market.id) LEFT OUTER JOIN contract T3 ON (market.id = T3.market_id) 
GROUP BY contract.id, contract.name, contract.market_id, contract.current_price, market.id, market.name 
HAVING contract.current_price = MAX(T3.current_price) 

Die API verwendet eine zusätzliche Verknüpfung statt einer Unterabfrage (wie Ihre Abfrage der Fall ist). Es ist schwierig zu sagen, welche Abfrage schneller ist, insbesondere ohne das Datenbanksystem zu kennen. Ich schlage vor, dass Sie einige Benchmarks machen und entscheiden.

+0

Ich hätte angenommen, dass die Unterabfrage effizienter als zwei JOINs ist, aber Sie haben Recht, dass das nicht angenommen werden sollte; benchmarken und sehen. –

+0

Ayman, danke! Als Django-Neuling brauchte ich eine Weile, bis es funktionierte :) Ich habe eine Frage zum Filter in der Aussage: Es gibt eine Möglichkeit für das -unheimlich-Ereignis, in dem Preise von mehr als einem Vertrag gleich sind. Wenn dies der Fall ist, wird die Abfrage sie alle abrufen und mehrere Verträge für einen Markt geben, oder? – shanyu

+0

@ozgur - In der Tat, wenn zwei Verträge den gleichen Preis haben (was auch das Maximum ist), werden beide zurückgegeben. –

Verwandte Themen