【问题标题】:Should I upload images to a static directory in Django?我应该将图像上传到 Django 中的静态目录吗?
【发布时间】:2014-06-20 21:17:35
【问题描述】:

我有一个包含图像字段的模型。

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

在我看来,我从指定的 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))

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

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

【问题讨论】:

    标签: python django file-upload permissions static-files


    【解决方案1】:

    FileFieldImageField 的文件是相对于 settings.MEDIA_ROOT 上传的,并且应该可以通过附加到 settings.MEDIA_URL 的相同相对文件名进行访问。这就是为什么您的管理界面指向错误的 url。出于安全原因,这些应该不同于STATIC_ROOTSTATIC_URL,否则Django 将引发ImproperlyConfiguredError

    这不会阻止用户访问他们不应该看到的文件,如果他们知道或可以猜到 URL。为此,您需要通过 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)
    

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

    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
    

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

    Django >= 1.5 应该使用新的StreamingHttpResponse 而不是HttpResponse

    【讨论】:

    • 非常感谢!我可以照常使用request.user 来检查权限吗?
    • 是的,如果您只允许用户查看自己的文件,这可能是最好的方法。
    猜你喜欢
    • 2014-08-03
    • 1970-01-01
    • 2014-05-02
    • 1970-01-01
    • 1970-01-01
    • 2016-04-04
    • 1970-01-01
    • 2019-07-31
    • 2011-03-28
    相关资源
    最近更新 更多