Вот мой запрос:

  • У меня есть модель Personne, которая может иметь одно или несколько путешествий через PersonneTravel.
  • В PersonneTravel поле travel является внешним ключом для TagWithValue
  • s - это "начальная" дата, например "1954-05-01"
  • e - дата окончания, например "1999-05-01"
  • travel - это строка типа "Париж, Франция"

Итак, я провожу основной «поиск», чтобы отфильтровать, кто и когда путешествовал.

Вот как я это делаю, и, поскольку я новичок в django, я почти уверен, что его можно оптимизировать:

  1. Я получаю все pk из TagWithValue, у которых есть соответствие value
  2. Я извлекаю все pk PersonneTravel, у которых есть путешествия, совпадающие с предыдущими
  3. Я получаю все Personne, которые соответствуют PersonneTravel pk до

Я хотел бы вернуть только одно такое соединение (это, конечно, не очень хороший sql , но просто для того, чтобы понять большую идею):

SELECT ALL PersonneTravel PT
JOIN Personne P on P.personne_travel__pk = PT.pk
JOIN TagWithValue T
WHERE T.personne__pk = P.pk
AND T.value = "Paris, France"
AND T.tag = TYPE_GOOGLEMAPS

Есть ли способ оптимизировать это и сделать это с помощью моего следующего кода?

q = Q()
if s:
    q = q & Q(date_start__gte=s)
if e:
    q = q & Q(date_end__lte=e)
retour = [a[0] for a in TagWithValue.objects.filter(
    type_tag__exact=BaseTag.TYPE_GOOGLEMAPS,
    value__exact=travel).values_list('pk')]
retour = PersonneTravel.objects.filter(Q(travel__in=retour) & q)\
    .values_list('personne__pk')
if len(retour):
    retour = Personne.objects.filter(pk__in=retour)
1
Olivier Pons 1 Мар 2016 в 01:34

2 ответа

Лучший ответ

Здесь нет необходимости использовать Q(). Используйте flat=True с values_list(), чтобы получить список значений вместо списка типов значений. Это решение можно еще больше упростить, используя related_name в столбце ForeignKey модели Django.

key = {}
if s:
    key['date_start__gte'] = s
if e:
    key['date_end__lte'] = e
key[travel__type_tag__exact] = BaseTag.TYPE_GOOGLEMAPS
key[travel__value__exact] = travel

retour = PersonneTravel.objects.filter(**key)\
    .values_list('personne__pk', flat=True)

if len(retour):
    retour = Personne.objects.filter(pk__id__in=retour)

Пример с related_name: скажем, related_personne - это связанное_имя для Personne соответственно в модели PersonneTravel.

key = {}
key['related_personne__travel__type_tag__exact'] = BaseTag.TYPE_GOOGLEMAPS
key['related_personne__travel__value__exact'] = travel
if s:
    key['related_personne__date_start__gte'] = s
if e:
    key['related_personne__date_end__lte'] = e

retour = Personne.objects.filter(**key)
1
Moinuddin Quadri 1 Мар 2016 в 07:00

Я думаю, вы можете обойтись без Q-objects, используя синтаксис django __:

query = Personne.objects.filter(personnetravel__travel__value__exact=travel,
                                personnetravel__travel__type_tag__exact=BaseTag.TYPE_GOOGLEMAPS) 

# because django querysets are lazy you can add the date filters now
if s:
    query = query.filter(personnetravel__date_start__gte=s)
if e:
    query = query.filter(personnetravel__date_end__lte=e)
0
ilse2005 29 Фев 2016 в 23:22