Search code examples
djangodjango-modelsdjango-autocomplete-light

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


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!


Solution

  • 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.