【问题标题】:Django media files not loading when debug is False on Cpanel当 Cpanel 上的调试为 False 时,Django 媒体文件未加载
【发布时间】:2021-06-28 14:43:44
【问题描述】:

我试图展示我的媒体文件一个多星期,并尝试了所有 stackoverflow 解决方案,但一无所获。我的项目托管在 Cpanel 上,我尝试为媒体提供绝对路径,尝试将它们放在 public_html 文件夹中,什么都没有。另外,我的静态文件可以毫无问题地提供,但媒体文件甚至没有显示在开发人员工具的源代码中(通常情况下应该有一个),当调试为真时它工作得很好,但当调试为假时它确实不是。请问有什么想法吗?

我的 settings.py 的一部分

import os
from django.contrib.messages import constants as messages
from decouple import config

# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))


# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/3.0/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = config('SECRET_KEY')
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = False
CSRF_COOKIE_SECURE = config('CSRF_COOKIE_SECURE')
SESSION_COOKIE_SECURE = config('SESSION_COOKIE_SECURE')


MIDDLEWARE = [
    'debug_toolbar.middleware.DebugToolbarMiddleware',
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'whitenoise.middleware.WhiteNoiseMiddleware'
]

STATIC_URL = '/static/'
STATICFILES_STORAGE = 'whitenoise.storage.CompressedStaticFilesStorage'

STATICFILES_DIRS = [
    os.path.join(BASE_DIR, "static")
    ]


STATIC_ROOT = os.path.join(BASE_DIR, 'assets')
CKEDITOR_UPLOAD_PATH = 'uploads/'
MEDIA_URL ='/media/'

MEDIA_ROOT = os.path.join(BASE_DIR, 'media')

INTERNAL_IPS = ['127.0.0.1', '::1', '0.0.0.0']

项目 urls.py

from django.contrib import admin
from django.urls import path, include
from django.conf.urls.static import static
from django.conf import settings


urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('main.urls')),
    path('panier/', include('cart.urls', namespace='cart')),
    path('commande/', include('orders.urls', namespace='orders')),
    path('ckeditor/', include('ckeditor_uploader.urls')),
    path('coupon/', include('coupons.urls', namespace='coupons'))

]
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

if settings.DEBUG:
    if settings.DEBUG == True:
        import debug_toolbar
        urlpatterns += [path('__debug__/', include(debug_toolbar.urls)),] 

我的一些模型

from django.db import models
from django.urls import reverse
from django.utils import timezone
import datetime
from django.db.models import F
from django.conf import settings
import os
from django.utils.deconstruct import deconstructible
from django.core.validators import MinValueValidator

from ckeditor.fields import RichTextField
from django.utils.safestring import mark_safe



PRODUCT_STATUS = (
    ('N', 'Nouveau'),
    ('P', 'Promotion'),
    ('S', 'Sans Status')
)


@deconstructible
class PathAndRename(object):
   def __init__(self, sub_path):
       self.path = sub_path

   def __call__(self, instance, filename):
       
       filename = 'product_{0}_{1}'.format(instance.user.id, filename)
       # return the whole path to the file
       return os.path.join(self.path, filename)

def solution_directory_path(instance, filename):
    date_fields = str(datetime.date.today()).split('-')
    year = date_fields[0]
    month = date_fields[1]
    day = date_fields[2]
    
    # file will be uploaded to MEDIA_ROOT/solutions/YEAR/MONTH/DAY/solution_id_<filename>
    solution_sub_path = 'solutions/{0}/{1}/{2}/solution_{3}_{4}'.format(year, month, day, instance.id, filename)
    solution_full_path = os.path.join(settings.MEDIA_ROOT, solution_sub_path)
    if os.path.exists(solution_full_path):
        os.remove(solution_full_path)
    return solution_sub_path

def product_directory_path(instance, filename):
    
    date_fields = str(datetime.date.today()).split('-')
    year = date_fields[0]
    month = date_fields[1]
    day = date_fields[2]
    # file will be uploaded to MEDIA_ROOT/produits/YEAR/MONTH/DAY/produit_<produit_id>_<filename>
    product_sub_path = 'produits/{0}/{1}/{2}/product_{3}_{4}'.format(year, month, day,instance.product_id, filename)
    product_full_path = os.path.join(settings.MEDIA_ROOT, product_sub_path)
    if os.path.exists(product_full_path):
        os.remove(product_full_path)
    return product_sub_path

def product_directory_path_second_picture(instance, filename):
    
    date_fields = str(datetime.date.today()).split('-')
    year = date_fields[0]
    month = date_fields[1]
    day = date_fields[2]
    # file will be uploaded to MEDIA_ROOT/produits/YEAR/MONTH/DAY/produit_<produit_id>_<filename>
    product_sub_path = 'produits/{0}/{1}/{2}/product_{3}_photo_2_{4}'.format(year, month, day,instance.product_id, filename)
    product_full_path = os.path.join(settings.MEDIA_ROOT, product_sub_path)
    if os.path.exists(product_full_path):
        os.remove(product_full_path)
    return product_sub_path

def product_file_directory_path(instance, filename):
    
    date_fields = str(datetime.date.today()).split('-')
    year = date_fields[0]
    month = date_fields[1]
    day = date_fields[2]
    # file will be uploaded to MEDIA_ROOT/produits/YEAR/MONTH/DAY/produit_<produit_id>_<filename>
    product_sub_path = 'fichers/{0}/{1}/{2}/product_{3}_{4}'.format(year, month, day,instance.product_id, filename)
    product_full_path = os.path.join(settings.MEDIA_ROOT, product_sub_path)
    if os.path.exists(product_full_path):
        os.remove(product_full_path)
    return product_sub_path


# custom product manager : have to use it for search filtering
class ProductManager(models.Manager):
    def get_queryset(self):
            return super(ProductManager, self).get_queryset()\
                    .filter(stock__gte=1, available=True)

class Solution(models.Model):
    
    name         = models.CharField( max_length=50)
    slug        = models.SlugField( max_length=70) 
    photo       = models.ImageField(verbose_name='Photo de la solution', upload_to=solution_directory_path, blank=True)
    photo_2     = models.ImageField(verbose_name='Photo 2 de la solution', upload_to=solution_directory_path, blank= True)
    description = RichTextField(verbose_name='Text en plus', blank= True, null=True)

    def __str__(self):
        return self.name
    def get_absolute_url(self):
        return reverse("produit", args=[self.slug])

class Category(models.Model):
    
    name = models.CharField(max_length=200, db_index=True)
    slug = models.SlugField(max_length=200, unique=True)
    
    class Meta:
        ordering = ('name',)
        verbose_name = 'Catégorie'
        verbose_name_plural = 'Catégories'
    
    def __str__(self):
        return self.name
    def get_absolute_url(self):
        return reverse("product-by-cat", args = [self.slug])
    

class Product(models.Model):
    
    product_id  = models.CharField(max_length= 50, blank=False, null= False, unique=True, default='',verbose_name='Numéro du Produit')
    name        = models.CharField(max_length=50, verbose_name = 'Nom du Produit', db_index=True)
    slug        = models.SlugField(max_length=70, verbose_name= 'Slug')
    solution    = models.ForeignKey(Solution, on_delete=models.SET_NULL, verbose_name='Solution', default='', null=True)
    category = models.ForeignKey(Category, on_delete= models.CASCADE, related_name="products" ,verbose_name='Catégorie')
    sub_title  = models.CharField(max_length=100, verbose_name=("Sous titre"), blank= True)
    description = RichTextField(verbose_name='Description', blank= True, null=True)
    sup_info    = RichTextField(verbose_name='Informations Supplémentaires', blank= True, null=True)
    photo       = models.ImageField(verbose_name='Photo du Produit', upload_to= product_directory_path, blank=True)
    photo_2     = models.ImageField(verbose_name='Photo du Produit 2', upload_to= product_directory_path_second_picture, blank=True)
    file_1   = models.FileField(verbose_name='Fiche Technique', upload_to=product_file_directory_path, blank= True)
    price = models.DecimalField(verbose_name='Prix', max_digits=10, decimal_places=2, validators = [MinValueValidator(0)], blank=False, null=False)
    available = models.BooleanField(verbose_name='Disponibilité', default=True)
    status = models.CharField(choices= PRODUCT_STATUS, max_length=50, default='S' , blank=False, null = False, verbose_name="Status")
    created = models.DateTimeField(verbose_name='Date de Création', auto_now_add=True)
    updated = models.DateTimeField(verbose_name='Date de dernière mise à jour', auto_now=True)
    stock = models.PositiveIntegerField(verbose_name='Stock', validators= [MinValueValidator(0)], default=0, blank=False, null=False ) 
    
    
    objects = models.Manager() # The default manager.
    show = ProductManager() # Our custom manager
    
    class Meta:
            ordering = ('name',)
            verbose_name = 'Produit'
            verbose_name_plural = 'Produits'

    def __str__(self):
        return self.name
    
    def get_absolute_url(self):
        return reverse("produits", args=[self.slug])
    
    def get_description(self):
        return mark_safe(self.description)
    
    def get_sup_info(self):
        return mark_safe(self.sup_info) 


class ContactForm(models.Model):
    name        = models.CharField(verbose_name='Nom complet', max_length=100)
    phone       = models.CharField(verbose_name="Téléphone" , max_length=25)
    email       = models.EmailField(verbose_name="Email", null=True, blank = True)
    subject     = models.CharField(verbose_name="Sujet", max_length=50, blank=False)
    message     = models.TextField(verbose_name="Sujet", blank=False, null=False)
    date_sent = models.DateTimeField(verbose_name="Date", auto_now_add=True)

    def __str__(self):
        return self.name

    class Meta:
        verbose_name = 'Formulaire de Contact'




class Post(models.Model):
    titre = models.CharField(max_length=200)
    slug = models.SlugField(max_length=100)
    intro = models.CharField(max_length=200, blank=True)
    image = models.ImageField(verbose_name='Image' ,upload_to='slides/', blank= True)
    text = RichTextField(verbose_name='Article', blank= True, null=True)
    created_date = models.DateTimeField(default=timezone.now)


    def __str__(self):
        return self.titre


【问题讨论】:

    标签: django deployment cpanel django-media


    【解决方案1】:

    您不能使用 whitenoise 来提供您的媒体文件:https://github.com/evansd/whitenoise/issues/62 您需要将您的服务器配置为让 apache 或 nginx 或类似的东西从您的媒体目录中提供这些媒体文件。

    【讨论】:

    • 我们可以在像 Cpanel 这样的共享主机上使用 apache 服务吗?
    • 我想是的。我不熟悉 cPanel,但我相信我听说过有人用它来服务器静态内容。如果您可以设置,那么您可以连接 Django 将媒体文件上传到该目录,以便网络可以访问它们。
    猜你喜欢
    • 2022-11-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-06-13
    • 2019-01-05
    • 2020-05-21
    • 2019-09-14
    • 2020-12-31
    相关资源
    最近更新 更多