Я использую пользовательский бэкенд кеша, чтобы обернуть встроенные бэкенды кеша, чтобы я мог добавить текущий site_id ко всем cache_keys (это полезно для многосайтовой функциональности с одним экземпляром memcached)
к сожалению, он отлично работает на встроенном сервере разработки django, но выдает неприятную ошибку, когда я пытаюсь запустить его на живом сервере с mod_wsgi.
Вот трассировка из моего журнала ошибок:
[Wed Feb 17 00:39:34 2010] [error] [client 127.0.0.1] mod_wsgi (pid=22933): Exception occurred processing WSGI script '/home/jiaaro/webapps/op_wsgi/myProject/deploy/myProject.wsgi'.
[Wed Feb 17 00:39:34 2010] [error] [client 127.0.0.1] Traceback (most recent call last):
[Wed Feb 17 00:39:34 2010] [error] [client 127.0.0.1] File "/home/jiaaro/webapps/op_wsgi/lib/python2.5/django/core/handlers/wsgi.py", line 230, in __call__
[Wed Feb 17 00:39:34 2010] [error] [client 127.0.0.1] self.load_middleware()
[Wed Feb 17 00:39:34 2010] [error] [client 127.0.0.1] File "/home/jiaaro/webapps/op_wsgi/lib/python2.5/django/core/handlers/base.py", line 40, in load_middleware
[Wed Feb 17 00:39:34 2010] [error] [client 127.0.0.1] mod = import_module(mw_module)
[Wed Feb 17 00:39:34 2010] [error] [client 127.0.0.1] File "/home/jiaaro/webapps/op_wsgi/lib/python2.5/django/utils/importlib.py", line 35, in import_module
[Wed Feb 17 00:39:34 2010] [error] [client 127.0.0.1] __import__(name)
[Wed Feb 17 00:39:34 2010] [error] [client 127.0.0.1] File "/home/jiaaro/webapps/op_wsgi/myProject/apps/site_settings/__init__.py", line 6, in <module>
[Wed Feb 17 00:39:34 2010] [error] [client 127.0.0.1] import cache_wrapper
[Wed Feb 17 00:39:34 2010] [error] [client 127.0.0.1] File "/home/jiaaro/webapps/op_wsgi/myProject/apps/site_settings/cache_wrapper.py", line 4, in <module>
[Wed Feb 17 00:39:34 2010] [error] [client 127.0.0.1] from django.core.cache.backends.base import BaseCache
[Wed Feb 17 00:39:34 2010] [error] [client 127.0.0.1] File "/home/jiaaro/webapps/op_wsgi/lib/python2.5/django/core/cache/__init__.py", line 73, in <module>
[Wed Feb 17 00:39:34 2010] [error] [client 127.0.0.1] cache = get_cache(settings.CACHE_BACKEND)
[Wed Feb 17 00:39:34 2010] [error] [client 127.0.0.1] File "/home/jiaaro/webapps/op_wsgi/lib/python2.5/django/core/cache/__init__.py", line 68, in get_cache
[Wed Feb 17 00:39:34 2010] [error] [client 127.0.0.1] return getattr(module, 'CacheClass')(host, params)
[Wed Feb 17 00:39:34 2010] [error] [client 127.0.0.1] AttributeError: 'module' object has no attribute 'CacheClass'
если я запускаю devserver на той же машине (живой сервер), он работает нормально... Я могу сделать это без проблем:
$ cd /home/jiaaro/webapps/op_wsgi/myProject
$ python2.5 manage.py runserver
и в отдельном сеансе ssh...
$ wget 127.0.0.1:8000
Страницы обслуживаются правильно, с использованием memcached и активной базы данных. Есть ли что-то другое в том, как mod_wsgi импортирует модули, о чем мне следует знать?
может быть, что-то об однопроцессном, однопоточном характере сервера разработки?
Я боролся с этим в течение нескольких дней, любая помощь будет оценена
Дополнительная информация:
- Виртуальный хостинг Webfaction (centos)
- Апач 2
- Питон 2.5
- Джанго 1.1.1
- mod_wsgi 2.5
- MySQL 5.0
Дополнительные сведения: - Я установил кеш-бэкенд (и он работает, поскольку вы можете видеть, что он импортирует правильный модуль в трассировке) - В модуле есть класс с именем «CacheClass»:
site_settings/cache_wrapper.py:
from django.conf import settings
CACHE_BACKEND = getattr(settings, 'CUSTOM_CACHE_BACKEND')
from django.core.cache.backends.base import BaseCache
class CacheClass(BaseCache):
from decorators import accept_site
def __init__(self, *args):
from django.core.cache import get_cache
self.WRAPPED_CACHE = get_cache(CACHE_BACKEND)
@accept_site
def add(self, site, key, *args):
return self.WRAPPED_CACHE.add(self._key(site, key),*args)
@accept_site
def get(self, site, key, *args):
return self.WRAPPED_CACHE.get(self._key(site, key),*args)
... (all the rest of the wrapped methods)
def _key(self, site, key):
from exceptions import NoCurrentSite
if not site:
raise NoCurrentSite
return "%s|%s" % (site.id, key)
Декоратор accept_site работает в сочетании с некоторым промежуточным программным обеспечением для определения текущего сайта. Они здесь:
декораторы.ру:
def accept_site(fn):
def decorator(self, *args, **kwargs):
site = kwargs.get('site', None)
try:
del kwargs['site']
except KeyError:
pass
from .middleware import get_current_site
site = site or get_current_site()
if not site:
raise NoCurrentSite("The current site is not available via thread locals, please specify a site with the 'site' keyword argument")
return fn(self, site, *args, **kwargs)
return decorator
и промежуточное ПО.py
try:
from threading import local
except ImportError:
from django.utils._threading_local import local
from django.conf import settings
from django.contrib.sites.models import Site
DEFAULT_SITE_ID = 1
_thread_locals = local()
def get_current_site():
return getattr(_thread_locals, 'site', None)
def set_current_site(site):
setattr(_thread_locals, 'site', site)
class SiteSettings(object):
"""Middleware that gets various objects from the
request object and saves them in thread local storage."""
def process_request(self, request):
if settings.DEBUG:
site_id = request.GET.get('site_id', DEFAULT_SITE_ID)
else:
site_id = DEFAULT_SITE_ID
current_site_domain = request.META["HTTP_HOST"]
try:
current_site = Site.objects.get(domain__iexact=current_site_domain())
except:
current_site = Site.objects.get(id=site_id)
set_current_site(current_site)
Все это работает с использованием devserver, с теми же настройками, что и сервер wsgi, и настроенным с тем же путем python (насколько я вижу)
На данный момент я надеюсь, что где-то создал цикл импорта (хотя это не имеет смысла, поскольку это происходит только на сервере разработки)
изменить: я нашел список различий между devserver и apache в документах django, в которых говорится:
Devserver добавляет установленные приложения в sys.path, а Apache — нет.
Может, это как-то связано?