djangodjango-modelsdjango-related-manager

Django: Setting def __str__ to a Related Model


Objective: I am trying to set the __str__ of a model to the name of a related model. The Profile model has a __str__ that returns "last name, first name" of the user. I would like the Inspector to return something similar with their inspector_number.

Currently: The __str__ is returning "users.Profile.None 12345" instead of the desired "Doe, John 12345".

This is one of my first times using related_name for a model and I seem to be missing something.

Model.py

class Profile(BaseModel):
    user = models.OneToOneField(User, on_delete=models.SET_NULL, null=True, blank=True)
    inspector = models.ForeignKey(Inspector, on_delete=models.SET_NULL, null=True, blank=True, related_name="inspector_profile")
    
    def __str__(self):
        return self.user.last_name + ", " + self.user.first_name



class Inspector(BaseModel):

...

    inspector_number = models.CharField(max_length=19, unique=True, editable=False, default=get_inspector_number)


    def __str__(self):
        ret = str(self.inspector_profile) + " " + str(self.inspector_number)
        return ret

Update: I was able to solve the issue by using if hasattr(self, 'inspector_profile'):. All of the records had the attribute but this seemed to correct my issue.


Solution

  • The reason this happens is because inspector is a ForeignKey. This means that an Inspector can have zero, one, or more related Profiles, and this also means that self.inspector_profile is not a Profile object, but a RelatedObjectManager that manages Profile objects. You can for example print all the related Profile names with:

    class Inspector(BaseModel):
        # …
        
        def __str__(self):
            profiles = [str(profile) for profile in self.inspector_profile.all()]
            return f'{" ".join(profiles)} {self.inspector_number}'

    But probably the main question is if an Inspector should be related to potentially multiple Profiles, and that the relation should not be a OneToOneField from Inspector to Profile.