Puzzle on Q objects and foreign keys

I have a model like this:

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

I have a function that is passed a list of filters, where each filter has the form {'type': something, 'value': x}. This function should return the ANDing result set all filters together:

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

Each substring has the boolean property "main". Each thing has 1 and only 1 Subthing, where main == True.

Now I need to add a filter that returns all Things that have Subthing, where main==True and subproperty==filter['value']

Can I do this as part of the Q object that I create? If not? The query that I get before my new filter can be quite large, so I need a method that does not include a loop through the results.

+4
source share
2 answers

This is a little easier to understand if you explicitly give your Subthings "related_name" in relation to Thing.

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

Now you can use the Django join syntax to create your Q object:

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

The inverse relationship has a default name of “subthing_set”, but I find it easier to follow if you give it a better name, such as “substrings”.

+2
source

Usage (instead of final_q=Q() at the beginning)

 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) 

should get what you want, you can also set up your loop to create a subals list and apply it after the loop.

subthing_set and automatically adds a related field added to Thing to access related subtitles.

you can assign another sibling name, for example

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

All Articles