I have a simple scenario. I pass a kwarg prop_name
and prop_func
into my class init that I want to turn into property such as:
class A:
def __init__(self, *args, prop_name=None, prop_func=None, **kwargs):
if prop_name is not None and prop_func is not None:
setattr(self, prop_name, property(prop_func))
super().__init__(*args, **kwargs)
Why cannot I then do something like:
a = A(prop_name='some_name', prop_func=lambda _: 1)
print(a.some_name)
The result is:
>>> <property object at 0x7feb3f27cf98>
However, this works:
class A:
some_name = property(lambda _: 1)
a = A()
print(a.some_name)
>>> 1
EDIT: Possible workaround to get the same bahaviour. Please correct if there is any practical difference.
class A:
def __init__(self, *args, prop_name=None, prop_func=None, **kwargs):
self._prop_name = prop_name
self._prop_func = prop_func
def __getattr__(self, item):
if item == self._prop_name:
return self._prop_func(self) # this solution does not accept arguments
super().__getattr__(self, item)
a = A(prop_name='some_name', prop_func=lambda _: 1)
print(a.some_name)
>>> 1
EDIT 2: Explanation of why this behaviour solution is required.
This behaviour is supposed to happen in a Mixin
for a django view. The goal is to be able to dynamically create related views between related objects. For example:
class Country(models.Model):
... some attributes ...
class City(models.Model):
country = models.ForeignKey(Country)
.... some attributes ...
It would be very nice if, directly in the view, we could refer to the City's object generically like so:
self.parent
I've done this in the Mixin that is now shown here, it's way out of scope. However, for convenience sake, it would also be nice if we could refer to this parent
object directly as the field name itself, ie:
self.continent # basically just calls self.parent
This makes the code very intuitive to read. An example of a very simplified view:
class CountryDetailView(ParentMixin, DetailView):
model = Country
parent_model = Continent
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['continent'] = self.continent # equivalent to self.parent
return context