Using .filter() on a constant expression
I have some gnarly AND/OR logic combining Q() objects but deep within the logic, I need to do a comparison of two constants. In an ideal world, the logic would look something like def age(self, age): ... & Q(12=as_of.month) & ... but that's invalid python. I *can* break out this rats' nest of logic into individual queries, evaluate the constant expression, conditionally OR the logic into the tree, then reassemble all the parts. However, that gets even uglier. Actual code is included below ("dob"="date of birth", "dod"="date of death"; the "as_of" is a datetime.date instance; part of the complication is that the month/day DOB/DOD can be absent and the year can be an approximate range, e.g. born between 1943 and 1947; and the age query can be for a single age or a range of ages, e.g. 47-52 years old) and I'm looking to make the magic happen at the two places marked "MAGIC HAPPENS HERE". I tried hacking it with Q(dob_month=F(str(as_of.month))-11) (since dob_month is known to be 1 at this point) but that gives me FieldError: Cannot resolve keyword '6' into field. Choices are: when I run my tests. Trying without wrapping the number in str() complains that my integer/month has no attribute .split() (which obviously it doesn't). Is there any way to include a constant comparison in a Q()? Thanks, -tim ## alive_q = use_as_of & ( # dob1 >= y1 Q(dob_year_min__gt=alive_y1) | ( Q(dob_year_min=alive_y1) & ( Q(dob_month=None) | Q(dob_month__gt=as_of.month) | ( Q(dob_month=as_of.month) & ( Q(dob_day=None) | Q(dob_day__gte=as_of.day) )) )) | ( Q(dob_month=1) & Q("""MAGIC HAPPENS HERE checking if as_of.month=12""") & ( Q(dob_day=None) | (Q(dob_day=1) & Q("""MAGIC HAPPENS HERE checking if as_of.day=31""")) )) ) & ( # dob2 < y2 Q(dob_year_max__lt=alive_y2) | ( Q(dob_year_max=alive_y2) & ( Q(dob_month=None) | Q(dob_month__lt=as_of.month) | ( Q(dob_month=as_of.month) & ( Q(dob_day=None) | Q(dob_day__lt=as_of.day) )) )) | ( Q(dob_year_max=alive_y2+1) & ( Q(dob_month=1) & ( Q(dob_day=None) | Q(dob_day__lt=1) )) )) dead_q = use_dod & ( # dob1 >= y1 Q(dob_year_min__gt=dead_y1) | ( Q(dob_year_min=dead_y1) & ( Q(dob_month=None) | Q(dod_month=None) | Q(dob_month__gt=F("dod_month")) | ( Q(dob_month=F("dod_month")) & ( Q(dob_day=None) | Q(dod_day=None) | Q(dob_day__gte=F("dod_day")) )) | ( Q(dob_month=1, dod_month=12) & ( Q(dob_day=None) | Q(dod_day=None) | Q(dob_day=1, dod_day=31) )) )) ) & ( # dob2 < y2 Q(dob_year_max__lt=dead_y2) | ( Q(dob_year_max=dead_y2) & ( Q(dob_month=None) | Q(dod_month=None) | Q(dob_month__lt=F("dod_month")) | ( Q(dob_month=F("dod_month")) & ( Q(dob_day=None) | Q(dod_day=None) | Q(dob_day__lt=F("dod_day")) )) )) ) master_q = (alive_q | dead_q) return self.get_query_set().filter(master_q) -- You received this message because you are subscribed to the Google Groups "Django users" group. To post to this group, send email to django-users@googlegroups.com. To unsubscribe from this group, send email to django-users+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/django-users?hl=en.
Re: Using .filter() on a constant expression
On Sat, Oct 15, 2011 at 9:52 PM, Tim Chase wrote: > I have some gnarly AND/OR logic combining Q() objects but deep > within the logic, I need to do a comparison of two constants. In an ideal > world, the logic would look something like > > def age(self, age): > ... & Q(12=as_of.month) & ... > > but that's invalid python. > > I *can* break out this rats' nest of logic into individual > queries, evaluate the constant expression, conditionally OR the > logic into the tree, then reassemble all the parts. However, > that gets even uglier. ... > Is there any way to include a constant comparison in a Q()? Q objects are definitely not meant to handle that -- they have to operate on some field in the database. Besides, if you need to compare two constants, and you have both of them available in python before you construct your query, then why would you want to compare them in SQL? If the point is to include or exclude some other conditions based on the calling parameters, then I would just use those parameters to construct the right query to begin with. I would think that breaking it into smaller, manageable pieces would make the code easier to understand, rather than uglier, but that's a matter of aesthetics, I suppose. If you don't want to do that, then just use python to selectively include or exclude the other Q objects (that you wanted to depend on your comparison): Using your code as a base, I would do something like this: (I don't know if this is correct; I get a headache trying to count all of the parentheses :) ) alive_q = use_as_of & ( # dob1 >= y1 Q(dob_year_min__gt=alive_y1) | ( Q(dob_year_min=alive_y1) & ( Q(dob_month=None) | Q(dob_month__gt=as_of.month) | ( Q(dob_month=as_of.month) & ( Q(dob_day=None) | Q(dob_day__gte=as_of.day) )) )) | ( *# MAGIC HAPPENS HERE* * ( Q(dob_month=1, dob_day=None) if as_of.month==12 else Q() ) |* * ( Q(dob_day=1) if as_of_day==31 else Q())* *# END MAGIC* )) ) & ( # dob2 < y2 Q(dob_year_max__lt=alive_y2) | ( Q(dob_year_max=alive_y2) & ( Q(dob_month=None) | Q(dob_month__lt=as_of.month) | ( Q(dob_month=as_of.month) & ( Q(dob_day=None) | Q(dob_day__lt=as_of.day) )) )) | ( Q(dob_year_max=alive_y2+1) & ( Q(dob_month=1) & ( Q(dob_day=None) | Q(dob_day__lt=1) )) )) -- Regards, Ian Clelland -- You received this message because you are subscribed to the Google Groups "Django users" group. To post to this group, send email to django-users@googlegroups.com. To unsubscribe from this group, send email to django-users+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/django-users?hl=en.
Re: Using .filter() on a constant expression
On 10/21/11 13:58, Ian Clelland wrote: If you don't want to do that, then just use python to selectively include or exclude the other Q objects (that you wanted to depend on your comparison): Using your code as a base, I would do something like this: (I don't know if this is correct; I get a headache trying to count all of the parentheses :) ) alive_q = use_as_of& ( # dob1>= y1 Q(dob_year_min__gt=alive_y1) | ( Q(dob_year_min=alive_y1)& ( Q(dob_month=None) | Q(dob_month__gt=as_of.month) | ( Q(dob_month=as_of.month)& ( Q(dob_day=None) | Q(dob_day__gte=as_of.day) )) )) | ( *# MAGIC HAPPENS HERE* * ( Q(dob_month=1, dob_day=None) if as_of.month==12 else Q() ) |* * ( Q(dob_day=1) if as_of_day==31 else Q())* *# END MAGIC* I like your solution! I didn't know "Q()" would behave as a null-op like you use here--are there docs somewhere on that? I ended up solving the problem by breaking the bits into named pieces (with pretty impenetrable names) and then conditionally "|"ing in the pieces at the right point before reassembling the whole mess. Thanks for your ideas. -tkc -- You received this message because you are subscribed to the Google Groups "Django users" group. To post to this group, send email to django-users@googlegroups.com. To unsubscribe from this group, send email to django-users+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/django-users?hl=en.