override __str__(self) of a model from an imported app
Asked Answered
C

2

6

I'm facing the following situation: I have a django project, which uses an outside app [App1]. Within App1, it has the following structure:

  1. abstract class 'Base':

    class Base(models.Model):
        """
        Base model with boilerplate for all models.
        """
    
        name = models.CharField(max_length=200, db_index=True)
        alternate_names = models.TextField(null=True, blank=True, 
        default='')
        ..............
        ..............
        class Meta:
            abstract = True
    
       def __str__(self):
            display_name = getattr(self, 'display_name', None)
            if display_name:
                return display_name
    
       return self.name
    
  2. abstract class based on 'Base', called 'AbstractClassA':

    class AbstractClassA(Base):
    
        display_name = models.CharField(max_length=200)
        ....
        ....
    
        class Meta(Base.Meta):
            abstract = True
    
        def get_display_name(self):
            ....
            ....
            return ....
    
  3. The non abstract class class ClassA(AbstractClassA)

Now, when I do a query in my view for this ClassA, for example:

    qs = ClassA.objects.filter(Q(name__icontains=query_term)....)
    return qs

I feed this qs into another outside app (autocomplete), so that when I type in 'xxxx' on my web form, the form would give me suggestions on available matches in the DB, based on this qs.

This all works great, the only thing is, the list of potential matches shown to me is the default representation of the ClassA objects, which I traced back to

   def __str__(self):
        display_name = getattr(self, 'display_name', None)
        if display_name:
            return display_name
        return self.name

defined in the base abstract model I've mentioned earlier. What I want is, to have something else displayed as the list of potential matches (e.g. instead of 'display_name' or 'name', show me 'fieldA' + ';'+ 'fieldB' of each filtered item in qs).

My thought was to override this __str__ method somewhere. But because both the upstream and downstream aspect of my process are done in outside apps that I don't want to modify directly (i.e. copy directly into my Django project and rewrite certain parts), I'm not sure how I could achieve my goal.

Is there any elegant way to do so?

Please let me know if anything is unclear, or if I could provide you with any further information. Thanks!

Chlorella answered 30/4, 2018 at 3:57 Comment(0)
I
3

From your question it is not clear if the non-abstract classes are written by you, but what you can do is to create a mixin and add that to the class signature of your concrete classes, such as:

class NiceStrMixin():
    def __str__(self):
        return self.display_name

then

class ClassA(AbstractClassA, NiceStrMixin):
     ...

If you don't have access to ClassA either, you can monkey patch AbstractClassA.

Iloilo answered 30/4, 2018 at 4:7 Comment(1)
Thanks you sir, Monkey Patching worked for me! (ClassA also in the outside app).Chlorella
A
7

Another approach besides Monkey Patching is to use Proxy models.

class MyClassA(ClassA):

    class Meta:
        proxy = True

    def __str__(self):
        return self.attribute

Then use MyClassA instead of ClassA.

Amalle answered 30/4, 2018 at 4:35 Comment(1)
This is a really good approach and can also be combined with the mixin method in my answer...Iloilo
I
3

From your question it is not clear if the non-abstract classes are written by you, but what you can do is to create a mixin and add that to the class signature of your concrete classes, such as:

class NiceStrMixin():
    def __str__(self):
        return self.display_name

then

class ClassA(AbstractClassA, NiceStrMixin):
     ...

If you don't have access to ClassA either, you can monkey patch AbstractClassA.

Iloilo answered 30/4, 2018 at 4:7 Comment(1)
Thanks you sir, Monkey Patching worked for me! (ClassA also in the outside app).Chlorella

© 2022 - 2024 — McMap. All rights reserved.