Pergunta

Eu tenho um modelo como este:

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

Eu tenho uma função que é passada uma lista de filtros, onde cada filtro é da forma { 'type': algo, 'valor': x}. Esta função deve retornar um conjunto de resultados Anding todos os filtros juntos:

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

Cada Subthing tem uma propriedade booleana 'main'. Cada coisa tem 1 e apenas 1 Subthing onde principal == True.

Agora eu preciso adicionar filtro que retorna todas as coisas que têm um Subthing onde main==True e subproperty==filter['value']

Posso fazer isso como parte do objeto Q Estou construindo? Se não como pessoa? O queryset eu chegar antes do meu novo filtro pode ser bastante grande, então eu gostaria de um método que não envolve looping sobre os resultados.

Foi útil?

Solução

É um pouco mais fácil de entender se você dá explicitamente seus Subthings um "related_name" em sua relação com a coisa

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

Agora, você usa Django juntar sintaxe para construir o seu objeto Q:

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

A relação inversa tem o nome default 'subthing_set', mas eu acho que é mais fácil de seguir, se você dar-lhe um nome melhor como 'subthings'.

Outras dicas

Usando (em vez de final_q=Q() no início)

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)

deve conseguir o que você quiser, você também pode ajustar o loop para construir a lista sub_vals e aplicá-lo após o loop.

subthing_set é e adicionados automaticamente campo relacionado adicionado à Coisa de acesso relacionados Subthings.

Você pode atribuir outro nome relacionado, por exemplo.

thing=models.ForeignKey(Thing,related_name='subthings')
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top