使用Django进行查询优化

时间:2016-02-29 22:34:39

标签: django django-queryset

这是我的疑问:

  • 我有一个Personne模型,可以通过PersonneTravel进行一次或多次旅行。
  • PersonneTravel中,travel字段是TagWithValue
  • 的外键
  • s是一个开始'约会" 1954-05-01"
  • e是" 1999-05-01"
  • 的结束日期
  • travel是一个字符串,如" Paris,France"

所以我做了一个基本的"搜索"过滤谁做了旅行和何时。

在这里我是如何做到这一点的,因为我是django的初学者,我非常确定它可以进行优化:

  1. 我检索了pk个匹配TagWithValue的{​​{1}}个value
  2. 我检索所有pk PersonneTravel之前与之前相匹配的旅行
  3. 我检索与Personne pk之前匹配的所有PersonneTravel
  4. 我想只返回一个这样的联接(当然这是不是很好的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)
    

2 个答案:

答案 0 :(得分:1)

此处无需使用Q()。将flat=Truevalues_list()一起使用可获取值列表,而不是值类型列表。可以使用Django模型的ForeignKey列中的related_name进一步简化此解决方案。

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 :(得分:0)

我认为您可以使用django的Q-objects语法在__之后执行此操作:

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)