Dear community,
here’s a question/thought about how you handle annotated fields.
Here’s my use case:
```
from django import models
class Person(models.Model):
given_name = models.CharField(max_length=100)
family_name = models.CharField(max_length=100)
# Some people prefer a different name
preferred_name = models.CharField(max_length=200, blank=True, null=True)
```
I’d like to have a field `full_name` that is annotated whenever I fetch data from the database (`@property def full_name(self): …` doesn’t work for me).
It should return the `preferred_name` (if present) or join `given_name` and `family_name`.
I was happy to accomplish this by using a custom manager:
```
from django.db.models.functions import Coalesce, Concat
from django.db.models import CharField, Value
class PersonManager(models.Manager):
def get_queryset(self):
qs = super().get_queryset()
# The annotation details don’t matter, actually.
return qs.annotate(
full_name=Coalesce(
F('preferred_name'),
Concat(F('given_name'), Value(' '), F('family_name')),
output_field=CharField()
)
)
# … and add `objects = PersonManager()` to person model.
```
When querying directly, this works nicely: `Person.objects.first().full_name` returns the full name.
Though, when following a reverse foreign key relation, things go wrong:
```
class Restaurant(models.Model):
name = models.CharField(max_length=100)
owner = models.ForeignKey(Person, on_delete=models.SET_NULL)
```
```
Restaurant.objects.first().owner.full_name
# gives an exception, because the custom manager’s code isn't executed.
```
I read that you can set the `base_manager_name` on the `Person`’s meta class, but I didn’t have luck with that either.
Moreover, you can’t use the `full_name` for ordering on the Person’s meta class.
Long story short: What’s your preferred way that allows access to annotated properties consistently?
(I was thinking about custom `AnnotatedCharField`s, `AnnotatedTextField`s etc. that allow defining annotated fields on the model itself. Tempting, huh?)
Looking forward to your comments!
Best regards
Julian