Search code examples
pythonpython-3.xdjangodjango-modelsjinja2

How to get value from the different django model in DTL?


I am having 3 different models - User, Thread and UserProfile.

User model contains information like ID, First_name and Last_name.

Thread model contains information like

class Thread(models.Model):
    first_person = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True, related_name='thread_first_person')
    second_person = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True,related_name='thread_second_person')
    updated = models.DateTimeField(auto_now=True)

and UserProfile model,

class UserProfile(models.Model):
    custom_user = models.OneToOneField(CustomUser, on_delete=models.CASCADE)
    picture = models.ImageField(default='profile_image/pro.png', upload_to='profile_image', blank=True)

when I am trying to get all the threads from Thread model and pass it from views.py to my HTML template then I can access User model fields like -

{{ thread.second_person.ID}} {{ thread.second_person.First_name}}

But how can I access picture field from UserProfile with the help of custom_user ?


Solution

  • I'm a little confused: you say you have three models User, Thread and UserProfile. But inside your UserProfile model you reference a CustomUser model as the one-to-one relationship for the custom_user field. Then in your Thread model you reference a plain User model as the FKs for the first_person and second_person fields. Do you have 3 models or 4?

    Assuming you only have 3 models, and that CustomUser is actually just User, then what you're trying to achieve should be doable. However you may need to change your conventions regarding related names to best practices in order to do so cleanly.

    I have set up the models I think you need roughly below, and the code needed to access the relevant parts of each model within the template layer:

    #models.py
    
    class User(AbstractBaseUser):
        # User Model Code
    
    
    class Thread(models.Model):
        first_person = models.ForeignKey(
            User, 
            on_delete=models.CASCADE, 
            null=True, 
            blank=True, 
            related_name='thread_first_persons' # Note the Plural 
        ) 
        # Related name for a FK is a one-to-many relationship 
        # (i.e. 1 User can be first_person on many threads) 
        # This may not be your desired behaviour, but it is possible on current set-up
        
        second_person = models.ForeignKey(
            User,
            on_delete=models.CASCADE,
            null=True,
            blank=True,
            related_name='thread_second_persons'
        ) # As above
        
        updated = models.DateTimeField(auto_now=True)
    
    
    class UserProfile(models.Model):
        user = models.OneToOneField(
            User, 
            on_delete=models.CASCADE
            related_name='user_profile'
        )
        # Note: custom_user is confusing nomenclature. 
        # The above is best practice for User <> UserProfile 1-to-1 relationships
        picture = models.ImageField(
            default='profile_image/pro.png', 
            upload_to='profile_image', 
            blank=True
        )
    

    Now when you want access to the UserProfile from the Thread object, you can do so as follows inside a template:

    {{ thread.second_person.user_profile.picture }}

    Side Note: in your views.py file, if you are sending just the thread to your template, then to save your database several queries I would optimise with the following select_related parameters:

    #views.py
    
    threads = Thread.objects.select_related(
        'first_person', 'first_person__user_profile', 
        'second_person', 'second_person__user_profile'
    ).all()
    
    thread = Thread.objects.select_related(
        'first_person', 'first_person__user_profile', 
        'second_person', 'second_person__user_profile'
    ).get(id=id)