我的这个模型包含一个图像字段。
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
在我看来,我从指定的网址下载图片并将其存储在图片字段中。为了测试,我使用测试用户作为外键。
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
,这是一个错误的位置,导致找不到页面。)
答案 0 :(得分:6)
FileField
和ImageField
的文件相对于settings.MEDIA_ROOT
上传,并且可以通过附加到settings.MEDIA_URL
的相同相对文件名访问。这就是您的管理界面指向错误网址的原因。出于安全原因,这些应该与STATIC_ROOT
和STATIC_URL
不同,否则Django会引发ImproperlyConfiguredError
。
这不会阻止用户访问他们不应该看到的文件,如果他们知道或可以猜到网址。为此,您需要通过Django而不是您选择的Web服务器来提供这些私有文件。基本上,您需要在Web根级别指定一个私有目录,如果用户有权查看该文件,则需要加载这些文件。 E.g:
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
。