how to get profile pic in navbar from logged in user to display

I’m trying to get the profile pic that the user uploaded in their profile to display in the navbar. This is dynamic as the user can change their profile pic. I can’t seem to figure out the template to make this work … here are some snippets…

the uploaded files work and are located in the media root under the profile_pics folder.

models.py

class CustomUser(AbstractUser):
    # custom user account with username as primary identifier   
    email = models.EmailField(unique=True)
    username = models.CharField(max_length=150, unique=True)
    password = models.CharField(max_length=30)
  
    objects = CustomUserManager()
    
    REQUIRED_FIELDS = ['email']
    USERNAME_FIELD = 'username'
    
    class Meta:
        verbose_name = 'user'
        verbose_name_plural = 'users'
       

class Profile(models.Model):
    user = models.OneToOneField(CustomUser, on_delete=models.CASCADE)
    bio = models.TextField()
    profile_pic = models.ImageField(upload_to='profile_pics', default='default.jpg')
    first_name = models.CharField(max_length=50)
    middle_name = models.CharField(max_length=50)
    last_name = models.CharField(max_length=50)
    date_of_birth = models.DateField(null=True, blank=True)
    avatar = models.ImageField(upload_to='avatars', default='default.jpg')
    primary_language = models.CharField(max_length=50)
    secondary_language = models.CharField(max_length=50)
    primary_phone_number = models.CharField(max_length=15, validators=[phone_regex])
    pager_number = models.CharField(max_length=15)
    work_department = models.ForeignKey('Department', on_delete=models.CASCADE, null=True, blank=True) 
    is_provider = models.BooleanField(default=False)
    is_patient = models.BooleanField(default=False)
    is_pcp = models.BooleanField(default=False)
    # address = models.ForeignKey('Address', on_delete=models.CASCADE, null=True, blank=True)
    social_security_number = models.CharField(max_length=15)
    tax_identification_number = models.CharField(max_length=15)
    street_number = models.CharField(max_length=10)
    street_name= models.CharField(max_length=100)
    apt_number = models.CharField(max_length=10, blank=True, null=True)    
    city = models.CharField(max_length=50, blank=True)
    state = models.CharField(max_length=50, choices=US_STATES)
    country = models.CharField(max_length=50)
    postal_code = models.CharField(max_length=10)
    
    def __str__(self):
        return self.user.username
    
    class Meta:
        verbose_name_plural = 'Profiles'
        verbose_name = 'Profile'

user_navbar.html

<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-bs-toggle="dropdown"
              aria-expanded="false">
              <div>
                {% if not user.is_authenticated %}
                <img src="{% static 'media/anon_user.png' %}" class="rounded-circle" height="35" alt="" loading="lazy" />
                {% else %}
                <img src="{{***?????***}}" class="rounded-circle" height="35" alt="" loading="lazy" />
                {% endif %}
               </div>
              {{ request.user.username }}
            </a>

HI,

Assuming you have set MEDIA_URL and MEDIA_ROOT correctly, you can access media files in your templates in this way:

{% if not user.is_authenticated %}
<img src="{% static 'media/anon_user.png' %}" class="rounded-circle" height="35" alt="" loading="lazy" />
{% else %}
<img src="{{ user.profile.profile_pic.url }}" class="rounded-circle" height="35" alt="{{ user.username }}" loading="lazy" />
{% endif %}

Opinion part

Unless you define related_name in your OneToOneField , Django will use lowercased model name to access related object. So, user.profile should work.

I would recommend setting related_name to profile to be more explicit:

class Profile(models.Model):
    user = models.OneToOneField(CustomUser, on_delete=models.CASCADE, related_name='profile')