0

I am working on an online bookstore app. I have a book details page that displays book information in a table, including the book cover image. I am having an issue where the images display correctly when I runserver, however a team member is unable to get the images to display after pulling my code from Github.

all books template:

{%  extends 'bookstore/main.html' %}
{% load crispy_forms_tags %}
{% load static %}
from .models import Product

{% block content %}
  <div class="container">  
      <p>
        <h1 style="text-align:center;color:green;"> 
            GeekText Complete List of Books<br>
        </h1>

        <h3 style="text-align:center;color:green;">
            Click the Book Name for More Details
        </h3>
      </p>
      
    <div class="container">
      <div class="col-md-12">
        <table id="myTable" class="table table-striped tablesorter">  
            <thead>  
                <tr>  
                    <th scope="col">ID #</td>  
                    <th scope="col">Book Title</td>  
                    <th scope="col">Genre</th>
                    <th data-sorter="false" scope="col">Cover Image</td>  
                    <th scope="col">Author</td> 
                </tr>  
            </thead>  
              
            <tbody>  
                {% for item in items %}
                <tr>  
                    <td scope="row">{{ item.id }}</td>   
                    <td><a href="{% url 'book_details_with_pk' id=item.id %}">{{ item.name }}</a></td>   
                    <td>{{ item.genre }}</td>
                    <td><img src="{% static item.image %}" width="75" height="100"/></td> 
                    <td>{{ item.author }}</td>    
                    
                    <td><a href="{% url 'addtocart' item.id %}" class="btn btn-primary">Add To Cart</a>
                </tr>  
                {% endfor %}
            </tbody>  
        </table>
        {% endblock %}
      </div>  
    </div> 
    </div> 

views.py

from django.shortcuts import render, redirect
from django.db.models import Q
from django.views.generic import TemplateView, ListView, View
from .models import Product
from .models import Author
from .models import Genre
from .models import CartProduct
from .models import Cart
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger

def all_books(request, id=None):
    item = Product.objects.get(id=id)
    context = {
        'items': Product.objects.all().order_by('id'),
        'id': item.id, 
        'name': item.name,
        'cover': item.image,
        'author': item.author,
    }
    
    return render(request,'bookstore/all_books.html', context)

urls.py

from django.urls import path
from . import views
from django.conf import settings
from django.conf.urls.static import static

urlpatterns = [
    path('all_books/', views.all_books, name="all_books"),
    path('book_details/', views.book_details, name="book_details"),
    path(r'^book_details/(?P<id>\d+)/$', views.book_details, name="book_details_with_pk"),
    path('books/', views.books, name="books"),
    path(r'^book_author/(?P<id>\d+)/$', views.book_author, name="book_author"),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

settings.py

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'crispy_forms',
    'apps.users',
    'apps.bookstore',
    'django_filters',
]

STATIC_URL = '/static/'
MEDIA_URL = '/media/'
STATICFILES_DIRS = [
    os.path.join(BASE_DIR, 'static')
]

models.py

class Product(models.Model): # model to create table on database products

    genre = models.ForeignKey(Genre,related_name='products',on_delete=models.CASCADE)
    author = models.ForeignKey('Author',related_name='authors',on_delete=models.CASCADE)
    name = models.CharField(max_length=200, db_index=True)
    slug = models.SlugField(max_length=200, db_index=True)
    image = models.ImageField(upload_to='static/media',blank=True)
    image2 = models.ImageField(upload_to='media/%Y/%m/%d',blank=True)
    image3 = models.ImageField(upload_to='media/%Y/%m/%d',blank=True)
    publisher = models.CharField(max_length=100, db_index=True)
    release_date = models.DateTimeField(null=True)
    description = models.TextField(blank=True)
    price = models.DecimalField(max_digits=10, decimal_places=2)
    created = models.DateTimeField(default=timezone.now)
    updated = models.DateTimeField(auto_now=True)
Ivan Starostin
  • 8,798
  • 5
  • 21
  • 39
sharb
  • 1

1 Answers1

0

models.ImageField - these are media files, not static.

They get affected by settings: MEDIA_ROOT, MEDIA_URL

What the docs say about MEDIA_ROOT:

Absolute filesystem path to the directory that will hold user-uploaded files.

Warning

MEDIA_ROOT and STATIC_ROOT must have different values.

And media files should not be mixed with static files in folders.

Media files should be referenced like that

<img src="{{ item.image.url }}" />

here image - your field name, for image2 it would be item.image2.url

You have mixed static and media files by these field options:

image = models.ImageField(upload_to='static/media',blank=True)
image2 = models.ImageField(upload_to='media/%Y/%m/%d',blank=True)
image3 = models.ImageField(upload_to='media/%Y/%m/%d',blank=True)

now some of media files (image2, image3) are reachable through MEDIA_URL (because they belong to MEDIA_ROOT folder), some (image) are not - because they belong to STATIC_ROOT folder. You have found a workaround - you reference image field by "{% static item.image %}" trick which can help overcoming wrong setup but is also not a right way.

Also, your teammate might be having troubles with accessing "static" files because the term static is being misused. Again, files stored in the ImageFields are not static and are not part of your project. They are supposed to be uploaded by users and never stored in git. If you want to share them - you have to share files already uploaded to your local /media/... folders somehow.

Static files are/can be something like:

  • favicon.ico
  • main.css
  • robots.txt
  • popup.js
  • top_banner.jpg

So:

  • change upload_to for image field
  • move already uploaded files to new folder (under media folder), update file paths in the db
  • fix the way you reference these media files in templates to ...image.url

see also:

Ivan Starostin
  • 8,798
  • 5
  • 21
  • 39