I too have seen computed properties poorly implemented as model functions/properties, only some of the time matched with an appropriate database selector. I think there's a lot of merit in the idea.
I don't agree with reimplementing lookups/transforms/funcs to produce the python version of a SQL concept. It's a leaky abstraction. Instead, I'd prefer the model author provides their python calculation: allowed_to_drink = models.CalculatedField(Q(age__gte=18), lambda c: c.age >= 18) There may be destructuring/serialisation issues (migrations/pickle) using lambda, unless we can ignore these model fields during deserialisation. On Thursday, 16 November 2017 03:32:32 UTC+11, [email protected] wrote: > > Hello. > > I think I just invented very useful feature. > I have the following model > > class Customer(models.Model): > age = models.IntegerField() > > I want to show special link in template for customer if she is allowed to > drink. > > class Customer(models.Model): > age = models.IntegerField() > > @property > def allowed_to_drink(self): > return self.age >= 18 > > And in template I can do > > {% if customer.allowed_to_drink %}. > > But in another view I want to show only those customers, who are allowed > to drink. > So, in view I write > > drinkers = [customer for customer in models.Customer.objects.all() if > customer.allowed_to_drink]. > > But what if I have one million customers? It is insane to check this field > on Python side instead of database side. > I use ORM: > models.Customer.objects.filter(age__gte=18).all() > > And DRY principle is now violated. > See, I have knowledge "allowed_to_drink -> (age >= 18) " and I want to > write in once, and then use both in ORM queries and object method. > > And I am not alone here: > > https://stackoverflow.com/questions/31658793/django-filter-query-on-with-property-fields-automatically-calculated > > https://stackoverflow.com/questions/2143438/is-it-possible-to-reference-a-property-using-djangos-queryset-values-list > > Here is what I suggest > > class Customer(models.Model): > age = models.IntegerField() > allowed_to_drink = models.CalculatedField(Q(age__gte=18)) > > # Using in ORM > Customer.objects.filter(allowed_to_drink=True) > # It actually converted to > Customer.objects.filter(Q(age__gte=18)) > > # Using it in code > Customer().allowed_to_drink > # This part a little bit tricky, since you will need to check in on Python > side. > # "age__gte" should be converted to > funcs = { > "gte": lambda instance, field, value: getattr(instance, field) >= value > } > instance_field, func = "age__gte".split("__") > funcs[func](instance, instance_field, 18) > > But we already have code to convert Q to SQL, so it should be easy to do > it for python. > > Some more ideas: > * "Q" may have lazy evalutation here for cases like > "models.CalculatedField(Q(date__gte=now()))". Could be implemented with > lambdas, or we can simply allow only literal here. > * With Postrges you can even store calculated field in database (it has > calculated column), but it works only for literals. > > I think this functionality should be supported by Django core because it > affects admin, forms (calculated fields can't be changed), migrations and > ORM. > > > *Ilya Kazakevich* > > PyCharm developer. > > > > http://www.jetbrains.com > > The Drive to Develop > > -- You received this message because you are subscribed to the Google Groups "Django developers (Contributions to Django itself)" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To post to this group, send email to [email protected]. Visit this group at https://groups.google.com/group/django-developers. To view this discussion on the web visit https://groups.google.com/d/msgid/django-developers/22eb7e7c-4e86-4886-a491-27d133d4ae2f%40googlegroups.com. For more options, visit https://groups.google.com/d/optout.
