Головоломка о предметах Q и иностранных ключах - PullRequest
4 голосов
/ 29 ноября 2009

У меня есть такая модель:

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()

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

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 есть логическое свойство 'main'. Каждая вещь имеет 1 и только 1 субстанцию, где main == True.

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

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

Ответы [ 2 ]

2 голосов
/ 29 ноября 2009

Немного легче понять, если вы явно дадите своим субтитрам "related_name" в их отношении к Вещи

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

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

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

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

1 голос
/ 29 ноября 2009

Использование (вместо 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 для доступа к связанным субтитрам.

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

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