13👍
There are two options here. The first is to create a method to look it up dynamically, but use the property
decorator so that other code can still use straight attribute access.
class MyModel(models.Model):
_first_name = models.CharField(max_length=100, db_column='first_name')
@property
def first_name(self):
return self._first_name or self.user.first_name
@first_name.setter
def first_name(self, value):
self._first_name = value
This will always refer to the latest value of first_name, even if the related User is changed. You can get/set the property exactly as you would an attribute: myinstance.first_name = 'daniel'
The other option is to override the model’s save()
method so that it does the lookup when you save:
def save(self, *args, **kwargs):
if not self.first_name:
self.first_name = self.user.first_name
# now call the default save() method
super(MyModel, self).save(*args, **kwargs)
This way you don’t have to change your db, but it is only refreshed on save – so if the related User object is changed but this object isn’t, it will refer to the old User value.
2👍
Although this does not meet all the OP’s requirements, in some use-cases where the fallback is needed in queryset filters (on the database level) it may be possible to use Django’s Coalesce()
class (docs).
The simplest solution in such a case might be queryset annotation (using the example from @daniel-roseman’s answer):
queryset = MyModel.objects.annotate(first_name=Coalesce('_first_name', 'user__first_name'))
Each item obtained from the queryset will then get a first_name
attribute, which has the value of _first_name
with a fallback (in case the value is null
) to user.first_name
.
That is, assuming your model has a user
relation.
This can be implemented e.g. in a custom manager and could also be used in conjunction with a property
approach.
A detailed example for a similar case (override instead of fallback) is provided in this SO answer.