Question

J'ai un modèle comme celui-ci:

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

J'ai une fonction à laquelle est transmise une liste de filtres dans laquelle chaque filtre est de la forme {'type': quelque chose, 'valeur': x}. Cette fonction doit renvoyer un ensemble de résultats ET tous les filtres ensemble:

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

Chaque sous-sol a une propriété booléenne 'main'. Chaque chose a 1 et seulement 1 Subthing où main == True.

Je dois maintenant ajouter un filtre qui renvoie toutes les choses qui ont un Subthing où main == True et sous-propriété == filter ['valeur']

Puis-je faire cela dans le cadre de l'objet Q que je suis en train de construire? Sinon comment d'autre? Le nombre de requêtes que je reçois avant mon nouveau filtre peut être assez volumineux; j'aimerais donc une méthode qui n'impliquerait pas une boucle sur les résultats.

Était-ce utile?

La solution

C’est un peu plus facile à comprendre si vous donnez explicitement à vos Subthings un "quotient". dans leur relation à la chose

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

Maintenant, vous utilisez rejoindre Django syntaxe pour construire votre objet Q:

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

La relation inverse a le nom par défaut 'subthing_set', mais je trouve qu'il est plus facile à suivre si vous lui donnez un meilleur nom comme 'subthings'.

Autres conseils

Utilisation (au lieu de final_q = Q () au début)

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)

devrait vous donner ce que vous voulez, vous pouvez également ajuster votre boucle pour construire la liste de sous-valeurs et l'appliquer après la boucle.

subthing_set est et le champ associé a été ajouté automatiquement. Il est ajouté à la rubrique Accès aux sous-objets associés.

vous pouvez attribuer un autre nom associé, par exemple

thing=models.ForeignKey(Thing,related_name='subthings')
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top