我正在使用 Django 开发一个网站/博客,并且正在找出正确的设置/设置。我在虚拟机中运行 Ubuntu Server 16.04 进行测试。我正在使用似乎是 Gunicorn 和 Nginx 以及 PostgreSQL 数据库的常见设置,并在 Digital Ocean Spaces 上托管静态和媒体文件。我也打算在 Digital Ocean 上托管该网站。
我从这里、这里、这里和这里的几个不同的指南中拼凑了一些东西。
我还使用Django-Imagekit来处理图像(url、调整大小等)并在 Django Admin 中管理所有内容。
我面临的问题是,当我上传图像(直接到图像表单或通过发布表单)并保存对象时,我最终会收到服务器错误(500)。如果我刷新页面,它就可以正常工作。这也发生在网站本身(即转到主页,服务器错误,刷新,没有错误)。
我的 Gunicorn 和 Nginx 日志中也绝对没有错误。
文件结构:
site
├── project
│ ├── gallery
│ │ ├── static
│ │ │ ├── gallery
│ │ │ │ ├── css
│ │ │ │ └── images
│ │ ├── templates
│ │ │ └── gallery
│ │ ├── admin.py
│ │ ├── models.py
│ │ ├── urls.py
│ │ └── views.py
│ ├── posts
│ │ ├── static
│ │ │ ├── posts
│ │ │ │ ├── css
│ │ │ │ └── images
│ │ ├── templates
│ │ │ └── gallery
│ │ ├── admin.py
│ │ ├── models.py
│ │ ├── urls.py
│ │ └── views.py
│ ├── project
│ │ ├── settings
│ │ │ ├── base.py
│ │ │ ├── development.py
│ │ │ ├── local.py
│ │ │ ├── production.py
│ │ │ └── testing.py
│ │ ├── urls.py
│ │ └── wsgi.py
│ ├── static
│ └── templates
画廊/models.py:
...
from imagekit.models import ImageSpecField
from imagekit.processors import ResizeToFit, ResizeToFill
...
class Watermark(object):
def process(self, image):
pass
class Image(models.Model):
original = ImageField(upload_to='images/%Y/%m/%d/')
large = ImageSpecField(source='original', processors=[Watermark(), \
ResizeToFit(width=2000, height=2000, upscale=False)], \
format='JPEG', options={'quality': 90})
medium=...
small=...
wide=...
home=...
upload_date = models.DateTimeField(null=True, editable=False)
def save(self):
if not self.id and not self.original:
return
if self.upload_date is None:
self.upload_date = timezone.now()
image = PIL.Image.open(self.original)
imgFormat = image.format
MAX_HEIGHT = 4000
MAX_WIDTH = 4000
# Resize image if over MAX pixels in either direction
(width, height) = image.size
if height > MAX_HEIGHT or width > MAX_WIDTH:
ratio = width / height
output = BytesIO()
if width > height:
width = MAX_WIDTH
height = int(width / ratio)
else:
height = MAX_HEIGHT
width = int(height * ratio)
size = (width, height)
image = image.resize(size, PIL.Image.ANTIALIAS)
image.save(output, format=imgFormat, quality=100)
self.original = InMemoryUploadedFile(output, 'ImageField', \
self.original.name, 'images/', sys.getsizeof(output), None)
super(Image, self).save()
帖子/模型.py:
class Post(models.Model):
title = models.CharField(max_length=75)
...
image = models.ForeignKey(Image, blank=True, null=True, \
on_delete=models.SET_NULL)
...
设置/base.py:
import os
BASE_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
SECRET_KEY = os.environ['SECRET_KEY']
DEBUG = True
ALLOWED_HOSTS = []
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'posts',
'gallery',
'taggit',
'ckeditor',
'storages',
'imagekit',
...
]
MIDDLEWARE = [
'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',
]
ROOT_URLCONF = 'project.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
'django.template.context_processors.media',
],
},
},
]
WSGI_APPLICATION = 'project.wsgi.application'
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = True
USE_TZ = True
设置/测试.py:
from project.settings.base import *
# Override base.py settings here
DEBUG = False
ALLOWED_HOSTS = ['*']
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': 'test',
'USER': 'user',
'PASSWORD': '****',
'HOST': 'localhost',
'PORT': '1234',
}
}
# DigitalOcean Spaces Settings
AWS_ACCESS_KEY_ID = '*****'
AWS_SECRET_ACCESS_KEY = '*****'
AWS_STORAGE_BUCKET_NAME = 'production-storage'
AWS_S3_ENDPOINT_URL = 'https://nyc3.digitaloceanspaces.com'
AWS_S3_OBJECT_PARAMETERS = {
'CacheControl': 'max-age=86400'
}
AWS_LOCATION = 'static_test/'
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'static', 'static'),
]
STATIC_URL = 'https://%s/%s/' % (AWS_S3_ENDPOINT_URL, AWS_LOCATION)
STATICFILES_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'
DEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'
IMAGEKIT_DEFAULT_IMAGE_CACHE_BACKEND = 'imagekit.imagecache.NonValidatingImageCacheBackend'
# Needed for CKEditor to work
AWS_QUERYSTRING_AUTH = False
venv/bin/gunicorn_start:
#!/bin/bash
NAME="project"
DIR=/home/user/site/project
USER=brandon
GROUP=brandon
WORKERS=3
BIND=unix:/home/user/run/gunicorn.sock
DJANGO_SETTINGS_MODULE=project.settings.testing
DJANGO_WSGI_MODULE=project.wsgi
SECRET_KEY='*****'
LOG_LEVEL=error
cd $DIR
source ../../venv/bin/activate
export SECRET_KEY=$SECRET_KEY
export DJANGO_SETTINGS_MODULE=$DJANGO_SETTINGS_MODULE
export PYTHONPATH=$DIR:$PYTHONPATH
exec ../../venv/bin/gunicorn ${DJANGO_WSGI_MODULE}:application \
--name $NAME \
--workers $WORKERS \
--user=$USER \
--group=$GROUP \
--bind=$BIND \
--log-level=$LOG_LEVEL \
--log-file=-
/etc/nginx/sites-available/项目:
upstream app_server {
server unix:/home/user/run/gunicorn.sock fail_timeout=0;
}
server {
listen 80;
# add here the ip address of your server
# or a domain pointing to that ip(like example.com or www.example.com)
server_name 192.168.1.179
keepalive_timeout 5;
client_max_body_size 4G;
access_log /home/user/logs/nginx-access.log;
error_log /home/user/logs/nginx-error.log;
location /static/ {
alias /home/user/site/project/static;
}
# checks for static file, if not found proxy to app
location / {
try_files $uri @proxy_to_app;
}
location @proxy_to_app {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://app_server;
}
}
任何帮助,将不胜感激。
编辑:
将 Debug 设置为 True 给了我以下错误。
该问题似乎与 Django-Imagekit 有关
Internal Server Error: /posts/
Traceback (most recent call last):
File "/home/user/venv/lib/python3.5/site-packages/django/template/base.py", line 882, in _resolve_lookup
current = current[bit]
TypeError: 'ImageCacheFile' object is not subscriptable
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/home/user/venv/lib/python3.5/site-packages/django/core/handlers/exception.py", line 41, in inner
response = get_response(request)
File "/home/user/venv/lib/python3.5/site-packages/django/core/handlers/base.py", line 187, in _get_response
response = self.process_exception_by_middleware(e, request)
File "/home/user/venv/lib/python3.5/site-packages/django/core/handlers/base.py", line 185, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/home/user/site/project/posts/views.py", line 39, in posts
return render(request, 'posts/posts.html', {'posts':posts, 'recentTags':recent_tags})
File "/home/user/venv/lib/python3.5/site-packages/django/shortcuts.py", line 30, in render
content = loader.render_to_string(template_name, context, request, using=using)
File "/home/user/venv/lib/python3.5/site-packages/django/template/loader.py", line 68, in render_to_string
return template.render(context, request)
File "/home/user/venv/lib/python3.5/site-packages/django/template/backends/django.py", line 66, in render
return self.template.render(context)
File "/home/user/venv/lib/python3.5/site-packages/django/template/base.py", line 207, in render
return self._render(context)
File "/home/user/venv/lib/python3.5/site-packages/django/template/base.py", line 199, in _render
return self.nodelist.render(context)
File "/home/user/venv/lib/python3.5/site-packages/django/template/base.py", line 990, in render
bit = node.render_annotated(context)
File "/home/user/venv/lib/python3.5/site-packages/django/template/base.py", line 957, in render_annotated
return self.render(context)
File "/home/user/venv/lib/python3.5/site-packages/django/template/loader_tags.py", line 177, in render
return compiled_parent._render(context)
File "/home/user/venv/lib/python3.5/site-packages/django/template/base.py", line 199, in _render
return self.nodelist.render(context)
File "/home/user/venv/lib/python3.5/site-packages/django/template/base.py", line 990, in render
bit = node.render_annotated(context)
File "/home/user/venv/lib/python3.5/site-packages/django/template/base.py", line 957, in render_annotated
return self.render(context)
File "/home/user/venv/lib/python3.5/site-packages/django/template/loader_tags.py", line 72, in render
result = block.nodelist.render(context)
File "/home/user/venv/lib/python3.5/site-packages/django/template/base.py", line 990, in render
bit = node.render_annotated(context)
File "/home/user/venv/lib/python3.5/site-packages/django/template/base.py", line 957, in render_annotated
return self.render(context)
File "/home/user/venv/lib/python3.5/site-packages/django/template/loader_tags.py", line 216, in render
return template.render(context)
File "/home/user/venv/lib/python3.5/site-packages/django/template/base.py", line 209, in render
return self._render(context)
File "/home/user/venv/lib/python3.5/site-packages/django/template/base.py", line 199, in _render
return self.nodelist.render(context)
File "/home/user/venv/lib/python3.5/site-packages/django/template/base.py", line 990, in render
bit = node.render_annotated(context)
File "/home/user/venv/lib/python3.5/site-packages/django/template/base.py", line 957, in render_annotated
return self.render(context)
File "/home/user/venv/lib/python3.5/site-packages/django/template/defaulttags.py", line 216, in render
nodelist.append(node.render_annotated(context))
File "/home/user/venv/lib/python3.5/site-packages/django/template/base.py", line 957, in render_annotated
return self.render(context)
File "/home/user/venv/lib/python3.5/site-packages/django/template/defaulttags.py", line 322, in render
return nodelist.render(context)
File "/home/user/venv/lib/python3.5/site-packages/django/template/base.py", line 990, in render
bit = node.render_annotated(context)
File "/home/user/venv/lib/python3.5/site-packages/django/template/base.py", line 957, in render_annotated
return self.render(context)
File "/home/user/venv/lib/python3.5/site-packages/django/template/base.py", line 1040, in render
output = self.filter_expression.resolve(context)
File "/home/user/venv/lib/python3.5/site-packages/django/template/base.py", line 708, in resolve
obj = self.var.resolve(context)
File "/home/user/venv/lib/python3.5/site-packages/django/template/base.py", line 849, in resolve
value = self._resolve_lookup(context)
File "/home/user/venv/lib/python3.5/site-packages/django/template/base.py", line 890, in _resolve_lookup
current = getattr(current, bit)
File "/home/user/venv/lib/python3.5/site-packages/imagekit/cachefiles/__init__.py", line 85, in url
return self._storage_attr('url')
File "/home/user/venv/lib/python3.5/site-packages/imagekit/cachefiles/__init__.py", line 75, in _storage_attr
existence_required.send(sender=self, file=self)
File "/home/user/venv/lib/python3.5/site-packages/django/dispatch/dispatcher.py", line 193, in send
for receiver in self._live_receivers(sender)
File "/home/user/venv/lib/python3.5/site-packages/django/dispatch/dispatcher.py", line 193, in <listcomp>
for receiver in self._live_receivers(sender)
File "/home/user/venv/lib/python3.5/site-packages/imagekit/registry.py", line 53, in existence_required_receiver
self._receive(file, 'on_existence_required')
File "/home/user/venv/lib/python3.5/site-packages/imagekit/registry.py", line 61, in _receive
call_strategy_method(file, callback)
File "/home/user/venv/lib/python3.5/site-packages/imagekit/utils.py", line 166, in call_strategy_method
fn(file)
File "/home/user/venv/lib/python3.5/site-packages/imagekit/cachefiles/strategies.py", line 15, in on_existence_required
file.generate()
File "/home/user/venv/lib/python3.5/site-packages/imagekit/cachefiles/__init__.py", line 94, in generate
self.cachefile_backend.generate(self, force)
File "/home/user/venv/lib/python3.5/site-packages/imagekit/cachefiles/backends.py", line 109, in generate
self.generate_now(file, force=force)
File "/home/user/venv/lib/python3.5/site-packages/imagekit/cachefiles/backends.py", line 96, in generate_now
file._generate()
File "/home/user/venv/lib/python3.5/site-packages/imagekit/cachefiles/__init__.py", line 103, in _generate
content.seek(0)
ValueError: I/O operation on closed file.