2009-11-28 5 views
4

У меня есть модель, как это:головоломка относительно объектов Q и внешних ключей

class Thing(models.Model): 
    property1 = models.IntegerField() 
    property2 = models.IntegerField() 
    property3 = models.IntegerField() 

class Subthing(models.Model): 
    subproperty = models.IntegerField() 
    thing = modelsForeignkey(Thing) 
    main = models.BooleanField() 

У меня есть функция, которая передается список фильтров, где каждый фильтр имеет вид { 'типа ': something,' value ': x}. Эта функция должна возвращать набор результатов Андинг все фильтры вместе:

final_q = Q() 
for filter in filters: 
     q = None 
     if filter['type'] =='thing-property1': 
      q = Q(property1=filter['value']) 
     elif filter['type'] =='thing-property2': 
      q = Q(property2=filter['value']) 
     elif filter['type'] =='thing-property2': 
      q = Q(property3=filter['value']) 
     if q: 
      final_q = final_q & q 
return Thing.objects.filter(final_q).distinct() 

Каждый Subthing имеет логическое свойство «главный». Каждая вещь имеет 1 и только 1 Subthing, где main == True.

теперь мне нужно добавить фильтр, который возвращает все вещи, которые имеют Subthing где main==True и subproperty==filter['value']

Могу ли я сделать это как часть Q объекта я строящейся? Если не так? Запрос, который я получаю до моего нового фильтра, может быть довольно большим, поэтому мне нужен метод, который не включает в себя цикл по результатам.

+0

есть опечатка, должны быть модели.ForeignKey() – Evgeny

ответ

2

Это немного легче понять, если вы явно даете Subthings на «related_name» в их отношении к Thing

class Subthing(models.Model): 
    ... 
    thing = models.ForeignKey(Thing, related_name='subthings') 
    ... 

Теперь вы используете Django join syntax для построения Q объекта:

Q(subthings__main=True) & Q(subthings__subproperty=filter['value']) 

Обратное соотношение имеет имя по умолчанию «subthing_set», но я считаю, что его легче следовать, если вы дадите ему лучшее имя, например «подглавы».

+0

Doh! По какой-то причине я искал гораздо более сложное решение, чем это! Кажется, это работает отлично. –

1

Использование (вместо final_q=Q() в начале)

final_q=Q(subthing_set__main=True) 
sub_vals = map(lambda v: v['value'], filters) 
if sub_vals: 
    final_q = final_q & Q(subthing_set__subproperty__in=sub_vals) 

должны получить, что вы хотите, вы можете также настроить цикл для создания списка sub_vals и применить его после цикла.

subthing_set и автоматически добавлено связанное поле, добавленное в Вещь для доступа к связанным субтитрам.

Вы можете назначить другое родственное имя, например.

thing=models.ForeignKey(Thing,related_name='subthings')