I handle that situation quite differently.
I have a model manager that annotates different fields to the queryset depending on when I need them.
For your example, I would have something like this:
class CustomerQuerySet(models.QuerySet):
def with_allowed_to_drink(self):
return self.annotate(allowed_to_drink=Case(When(age__gte=18, then=True), default=False))
Then I actually created a decorator that applies the manager to instances on a model. It is not as generic as it could be since it depends on function names having the word “with” in them, but I’m sure we could make it more general.
def
queryset_on_instance(model: Model):
"""Takes the queryset of a model and creates new properties for each instance of the model based on
the custom queryset class. Some code is copied from django.models.managers; most of this was inspired by it.
The queryset methods that are copied must have 'with' in their name.
Tip: Use this as a decorator on model classes
"""
def create_method(method_name):
def the_method(self):
return
getattr(model._default_manager,
method_name)().get(pk=self.pk)
return the_method
queryset_class = getattr(model._default_manager,
"_queryset_class", None)
predicate = inspect.isfunction
for name,
method in
inspect.getmembers(queryset_class,
predicate=predicate):
if
'with' in
name:
# Only copy missing attributes.
if hasattr(model,
name):
continue
# Only copy public methods or methods with the attribute `queryset_only=False`.
queryset_only =
getattr(method,
'queryset_only', None)
if queryset_only
or (queryset_only
is None and name.startswith('_')):
continue
# Copy the method onto the model.
setattr(model,
name,
create_method(name))
return model
And then on your Customer model:
@queryset_on_instance
class Customer(models.Model):
age = models.IntegerField()
objects = CustomerQuerySet.as_manager()
In your code or template, you would access the value like so:
customer.with_allowed_to_drink.allowed_to_drink
And you can filter by the value like so:
Customers.objects.with_allowed_to_drink().filter(allowed_to_drink=True)
I do agree that it would be nice to have something out of the box that could handle custom properties in the QuerySet calls, or, as you put it, calculated fields.
--
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
django-develop...@googlegroups.com.
To post to this group, send email to
django-d...@googlegroups.com.
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/58aa034b-99de-4bad-98e4-5c200501b777%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
To unsubscribe from this group and stop receiving emails from it, send an email to django-developers+unsubscribe@googlegroups.com.
To post to this group, send email to django-developers@googlegroups.com.
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/58aa034b-99de-4bad-98e4-5c200501b777%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
--
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 django-developers+unsubscribe@googlegroups.com.
To post to this group, send email to django-developers@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-developers/2ea79561931841e59e6e5d59b1cbd631%40ISS1.ISS.LOCAL.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-developers/CAFNZOJNETxp5zzkqNVxs_RHCxi6s8dewcYB4TOW_MR-R60i8iw%40mail.gmail.com.
--
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 django-developers+unsubscribe@googlegroups.com.
To post to this group, send email to django-developers@googlegroups.com.
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/fdf87ea3-aa91-452a-8336-d73dc92efe8d%40email.android.com.
Such computations always end up slightly different in some
edge cases
There are some hard problems if trying to push all computations to the db. First problem is that this won't work for unsaved models. Second, if the value isn't fetched on initial select, the database values might change. This is almoust the same problem as when changing values on Python side. Finally, accessing the db just to do a simple computation isn't a good from performance perspective.
For using Python in the DB, on PostgreSQL Python isn't available in hosted environments as Python can access the db machine.
I'd take a look on what it requires to implement this feature as 3rd party addition, and then do the required changes to core.
- Anssi