Search code examples
djangoherokudjango-modelsstaticstatic-methods

Displaying image urls during iteration without using the url method


I'm trying to deploy a Django Blog I built to Heroku, but I'm having some issues displaying the thumbnail images of blog posts when rendering my templates. When I first developed the app I was using {{ post.thumbnail.url }} to render the images, and everything was working fine. Now that I've deployed to Heroku I'm swimming in broken links.

From [this post][1] I've learned that The "image.url" format in the html does not work on staticfiles/Heroku. That means I would need to use {% static "image url" %} to display the images.

The problem is: I'm rendering these posts and their images by iterating over a queryset of posts I'm passing to my templates. Eg:

{% for post in most_recent %}
<a href="{{ post.get_absolute_url }}">
  <div class="item d-flex align-items-center">
    <div class="image"><img src="{{ post.thumbnail.url }}" alt="..." class="img-fluid"></div>
    <div class="title"><strong>{{ post.title }}</strong>
      <div class="d-flex align-items-center">
        <div class="views"><i class="icon-eye"></i>{{ post.view_count }} </div>
        <div class="comments"><i class="icon-comment"></i>{{ post.comment_count }}</div>
      </div>
    </div>
  </div></a>
{% endfor %}

How can I get the url of the post's thumbnail image without using the url method?

This is what the model looks like:

class Post(models.Model):
    title = models.CharField(max_length=100)
    overview = models.TextField()
    timestamp = models.DateTimeField(auto_now_add=True)
    #comment_count = models.IntegerField(default=0)
    #view_count = models.IntegerField(default=0)
    author = models.ForeignKey(Author,on_delete=models.CASCADE)
    thumbnail = models.ImageField()
    categories = models.ManyToManyField(Category)
    featured = models.BooleanField()
    content = HTMLField()
    previous_post = models.ForeignKey('self', related_name='previous', on_delete=models.SET_NULL, blank=True, null=True)
    next_post = models.ForeignKey('self', related_name='next', on_delete=models.SET_NULL, blank=True, null=True)


    def __str__(self):
        return self.title
    
    def get_absolute_url(self):
        return reverse('post-detail', kwargs={
            'id': self.id
        })
    
    def get_update_url(self):
        return reverse('post-update', kwargs={
            'id': self.id
        })

    def get_delete_url(self):
        return reverse('post-delete', kwargs={
            'id': self.id
        })
        
    @property
    def get_comments(self):
        return self.comments.all().order_by('-timestamp')

    @property
    def view_count(self):
        return PostView.objects.filter(post=self).count()

    @property
    def comment_count(self):
        return Comment.objects.filter(post=self).count()

Settings set up:

# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.0/howto/static-files/

STATIC_URL = '/static/'
MEDIA_URL = '/media/'
STATICFILES_DIRS = [
    os.path.join(BASE_DIR, 'static_in_env')
]
VENV_PATH = os.path.dirname(BASE_DIR)
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
MEDIA_ROOT = os.path.join(BASE_DIR, 'media_root')
STATICFILES_STORAGE = 'whitenoise.django.GzipManifestStaticFilesStorage'

Here is a link to the full project: https://github.com/Kaizen91/ProgramaticLearning In case you'd like to experiment. [1]: Images(Media) not displaying on django-heroku server


Solution

  • After digging in to the Whitenoise documentation. http://whitenoise.evans.io/en/stable/django.html I found that you cannot use whitenoise to host user uploaded files/ media files. In order to have access to those files in a production environment you need to use a service like Amazon S3, Azure Storage, and Rackspace CloudFiles.