Головоломка о предметах Q и иностранных ключах
-
06-07-2019 - |
Вопрос
У меня есть такая модель:
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()
У меня есть функция, которой передается список фильтров, где каждый фильтр имеет форму {'type': 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 есть булево свойство main. Каждая вещь имеет 1 и только 1 подраздел, где main == True.
Теперь мне нужно добавить фильтр, который возвращает все вещи, у которых есть Subthing, где main == True
и subproperty == filter ['value']
Могу ли я сделать это как часть объекта Q
, который я создаю? Если нет, то как? Набор запросов, который я получаю до того, как мой новый фильтр может быть довольно большим, поэтому я хотел бы использовать метод, который не включает циклический просмотр результатов. Р>
Решение
Это немного легче понять, если вы явно дадите своим субтитрам " 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».
Другие советы
Использование (вместо 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')