我应该将图像上传到Django中的静态目录吗?

dan*_*jar 2 python django permissions file-upload static-files

我有这个包含图像字段的模型.

from django.db import models
from django.contrib.auth.models import User


class Customer(models.Model):
    user = models.ForeignKey(User)
    name = models.CharField(max_length=127)
    logo = models.ImageField(upload_to='customer/logo', null=True, blank=True)

    def __str__(self):
        return self.name
Run Code Online (Sandbox Code Playgroud)

在我看来,我从指定的URL下载图像并将其存储在图像字段中.为了测试,我使用测试用户作为外键.

import json
import urllib.request

from django.core.files.base import ContentFile
from django.http import HttpResponse
from django.contrib.auth.models import User

from customer.models import Customer


def create(request):
    values = json.loads(request.body.decode('utf-8'))
    values['user'] = User.objects.get(id=1)
    values['logo'] = ContentFile(urllib.request.urlopen(values['logo']).read(),
                                                                    'test.png')
    model = Customer.objects.create(**values)
    return HttpResponse('Created customer with ' + str(values))
Run Code Online (Sandbox Code Playgroud)

图像customer/logo/test.png按预期上传.现在,我如何在前端显示这些图像?我可以将它们保存到静态文件目录中,但只有相关用户才能访问它.

(顺便说一句,Django管理界面显示有一个文件为该Customer对象上传.但它链接到http://localhost:8000/admin/customer/customer/20/customer/logo/test.png一个错误的位置,并导致一个未找到的页面.)

knb*_*nbk 6

for FileField和的文件ImageField相对于上传,settings.MEDIA_ROOT并且应该可以通过附加到的相同的相对文件名访问settings.MEDIA_URL.这就是您的管理界面指向错误网址的原因.出于安全原因,这些应该与STATIC_ROOT和不同STATIC_URL,否则Django会提出一个ImproperlyConfiguredError.

这不会阻止用户访问他们不应该看到的文件,如果他们知道或可以猜到网址.为此,您需要通过Django而不是您选择的Web服务器来提供这些私有文件.基本上,您需要在Web根级别指定一个私有目录,如果用户有权查看该文件,则需要加载这些文件.例如:

from django.core.files.storage import FileSystemStorage

PRIVATE_DIR = os.path.join(ROOT_DIR, 'web-private')
fs = FileSystemStorage(location=PRIVATE_DIR)

class Customer(models.Model):
    logo = models.ImageField(upload_to='customer/logo', storage=fs, null=True, blank=True)
Run Code Online (Sandbox Code Playgroud)

在您的视图中,您必须提供此文件.我当前项目中的一个自定义应用程序使用以下函数发送静态文件:

import mimetypes
from django.http import HttpResponse # StreamingHttpResponse
from django.core.servers.basehttp import FileWrapper

def send_file(file):
    """
    Send a file through Django without loading the whole file into
    memory at once. The FileWrapper will turn the file object into an
    iterator for chunks of 8KB.
    """
    filename = file.name
    if settings.PRIVATE_MEDIA_USE_XSENDFILE:
        # X-sendfile
        response = HttpResponse()
        response['X-Accel-Redirect'] = filename  # Nginx
        response['X-Sendfile'] = filename        # Apache 2, mod-xsendfile
        # Nginx doesn't overwrite headers, but does add the missing headers.
        del response['Content-Type']
    else:
        # Can use django.views.static.serve() method (which supports if-modified-since),
        # but this also does the job well, as it's mainly for debugging.
        mimetype, encoding = mimetypes.guess_type(filename)
        response = HttpResponse(FileWrapper(file), content_type=mimetype)
        response['Content-Length'] = os.path.getsize(filename)
    return response
Run Code Online (Sandbox Code Playgroud)

然后send_file(customer.logo)在您的视图中使用.

Django> = 1.5应该使用new StreamingHttpResponse而不是HttpResponse.