Como posso fazer essa consulta SQL complexa usando o Django ORM? (Sub-quaria com uma junção)
Pergunta
Estou acostumado a escrever minhas próprias consultas SQL e estou tentando me acostumar com toda a coisa do ORM que parece ser tão popular hoje em dia.
Aqui está a consulta:
SELECT * FROM routes WHERE route_id IN (
SELECT DISTINCT t.route_id FROM stop_times AS st
LEFT JOIN trips AS t ON st.trip_id=t.trip_id
WHERE stop_id = %s
)
onde %s é um número inteiro.
Estou usando o ORM padrão do Django. Qual é a maneira mais pitônica de fazer isso?
Algumas informações em segundo plano: o banco de dados que estou usando é de um GTFS (Google Transit Feed Specification). Esta consulta deve obter uma lista de cada route
isso passa por um determinado stop
, no entanto, as informações que ligam isso estão no trips
tabela.
Essa consulta funciona muito bem para mim, então a única razão pela qual estou pedindo é aprender.
Obrigado!
Solução
Provavelmente seria um pouco mais fácil descobrir a maneira apropriada de fazer isso se você tivesse o que estava usando para o relevante Models
.
Estou assumindo algo como o seguinte, com base nas especificações que você mencionou trabalhando:
class Route(models.Model):
#bunch of stuff
pass
class Stop(models.Model):
#bunch of stuff
stop_times = models.ManyToManyField(through=StopTime)
class StopTime(models.Model):
trip = models.ForeignKey(Trip)
stop = models.ForeignKey(Stop)
# bunch of additional meta about this M2M table
pass
class Trip(models.Model):
route = models.ForeignKey(Route)
# bunch of stuff
Se for esse o caso ... você deve ser capaz de fazer algo como
Route.objects.filter(trip__stop__id=my_stop_id)
para conseguir tudo Route
objetos que passam por um dado Stop
com uma chave primária id
igual a my_stop_id
, que estou assumindo que é um número inteiro de acordo com sua postagem.
Peço desculpas se a sintaxe estiver um pouco fora, pois não precisava fazer relacionamentos muitos para muitos usando uma tabela extra explícita. Alguns ajustes também podem ser necessários se você precisar (ou optar por) usar o related_name
Parâmetro para qualquer tecla estrangeira ou para muitos para muitos.
Outras dicas
Corrija -me se eu estiver errado, mas acho que você não pode fazer isso com o Django Orm de maneira normal.
Não há suporte de subconsulta e, com uma junção normal, dependeria do seu banco de dados se um distinto pudesse ajudá -lo. Se você estiver usando o PostGres, poderia fazê -lo com este patch: http://code.djangoproject.com/ticket/6422
A consulta seria algo assim:
Route.objects.filter(stop_time__trips__stop_id=...).distinct('stop_time__route_id')