Сашко Лихенко Сашко Лихенко - 3 months ago 9
Python Question

How to write common implementation of __str__ method for all my models in Django?

I want all my models to override

__str__
method in similar fashion:

class MyModel1(models.Model):
name = models.CharField(max_length=255)

def __init__(self):
self.to_show = 'name'

def _show(self):
if hasattr(self,self.to_show):
return str(getattr(self, self.to_show))
else:
return str(getattr(self, 'id'))

def __str__(self):
return self._show()

class MyModel2AndSoOn(models.Model):
another_param = models.CharField(max_length=255)
# same implementation of `__str__` but with another_param


I do not want to repeat the same code for all my models so I tried inheritance:

class ShowModel(models.Model):
name = models.CharField(max_length=255)

def __init__(self):
self.to_show = 'name'

def _show(self):
if hasattr(self,self.to_show):
return str(getattr(self, self.to_show))
else:
return str(getattr(self, 'id'))

def __str__(self):
return self._show()

class MyModel1(ShowModel):
another_param = models.CharField(max_length=255)

class MyModel2(ShowModel):
another_param = models.CharField(max_length=255)


but it messes with
id
of
MyModel1
and
MyModel2
by replacing
id
with a pointer to
ShowModel
. How to write common implementation of
__str__
method for my models without inheritance or how to prevent treating
ShowModel
class as a Django model?

Upd: I used
abstract
model as alecxe suggested but it ended with an error message:

in _show
return str(getattr(self, self.to_show))
File "/path/to/my/project/env3/lib/python3.5/site-packages/django/db/models/fields/__init__.py", line 188, in __str__
model = self.model
AttributeError: 'CharField' object has no attribute 'model'


Upd Everything works fine if I assign value to the
name
field of my model object. Whole solution:

class ShowModel(object):
to_show = 'name'

def _show(self):
if hasattr(self,self.to_show):
return str(getattr(self, self.to_show))
elif hasattr(self,'id'):
return str(getattr(self, 'id'))
else:
return str(self)

def __str__(self):
return self._show()

class Meta:
abstract = True

class MyModel1(ShowModel):
name = models.CharField(max_length=255)
to_show = 'name'

class MyModel2(ShowModel):
another_param = models.CharField(max_length=255)
to_show = 'another_param'


in test case:

ua = MyModel1()
ua.name = 'hi'
print(ua)
#prints hi

ub = MyModel2()
ub.another_param = 'hi again'
print(ub)
#prints hi again

Answer

You need to create an abstract model:

class ShowModel(models.Model):
    name = models.CharField(max_length=255)

    def __init__(self):
        self.to_show = 'name'

    def _show(self):
        if hasattr(self, "show"):
            return str(getattr(self, "show"))
        else:
            return str(getattr(self, 'id'))

    def __str__(self):
        return self._show()

    class Meta:
        abstract = True

And, as for your follow-up question and thanks to @itzmeontv, you should replace self.to_show with "show" when calling hasattr() and getattr().