如何在 Hostgator 上安装 Django?
How to install Django on Hostgator?
我在 Hostgator 上看到可以在他们的托管服务上安装 Django,我已经联系了实时支持并回复说他们对此无能为力。
有人做过吗?
基本步骤是您需要 VPS 托管,http://www.hostgator.com/vps-hosting,除非他们已经为您完成,否则您将无法在他们的正常托管平台上安装 Django .
设置 VPS 后,您将拥有 SSH 凭据以登录到 Linux 主机。 (你应该在 Windows 上为此使用 PuTTY)。通过 SSH 连接到服务器后,您可以按照 Django 教程 (https://docs.djangoproject.com/en/1.8/intro/install/) 中的说明安装 Django。 (及其依赖项)
可以在 Windows 上开发 Django 应用程序,但比在 linux 主机上开发更难。这是一个意见。
HostGator 上的 Django 共享是可能的。这有点棘手,因为 Django 放弃了对 FastCGI 的支持。
使用 HostGator 自己的说明来设置 Django。
http://support.hostgator.com/articles/django-with-fastcgi#shared-reseller
但在此之前 运行 您需要将对 FastCGI 的支持修补回 Django。
- 幸运的是,Django 在一次提交中删除了所有 FastCGI:
https://github.com/django/django/commit/41f0d3d3bc8b0a6831530e1176c6415f9ba45b0b.patch
- 此补丁需要逆向移植以指向您拥有的版本。
这种需要检查 django 源项目并使用 git.
- 不要担心消除 docs 和 tests 子文件夹的冲突,因为无论如何都需要将它们排除在重新 FastCGI 化补丁之外。
- 为 HostGator 中安装的 Django 版本准备好补丁文件后,使用 git apply 将 FastCGI 支持重新注入到位于虚拟环境中的 Django 代码中
./mydjango/lib/python2.7/site-packages/django
- 最后是我为 Django 版本 1.10.1 得到的补丁文件。
- 使用 PyMySQL 而不是标准 mysql 库。 PyMySQL 是一个纯粹的 python mysql 客户端,因为 Host Gator 不提供 gcc。
- 安装库:
pip install PyMySQL
- Monkey 在 manage.py 和 index.fcgi 中通过在 #! python行:
#monkey patch importing pymysql
try:
import pymysql
pymysql.install_as_MySQLdb()
except ImportError:
pass
#Re-fast-cgi-ification-patch
From 51278286d278568dfe89263cad624204c01fa065 Mon Sep 17 00:00:00 2001
From: Joshua
Date: Tue, 6 Sep 2016 18:19:20 -0400
Subject: django folder only</p>
Revert "Removed FastCGI support per deprecation timeline; refs #20766."
This reverts commit 41f0d3d3bc8b0a6831530e1176c6415f9ba45b0b.
# Conflicts:
# django/core/management/__init__.py
# docs/howto/deployment/wsgi/index.txt
# docs/man/django-admin.1
# docs/ref/django-admin.txt
# tests/.coveragerc
# Conflicts:
# docs/man/django-admin.1
# docs/ref/django-admin.txt
diff --git a/django/conf/global_settings.py b/django/conf/global_settings.py
index 576ff6b..8d1461f 100644
--- a/django/conf/global_settings.py
+++ b/django/conf/global_settings.py
@@ -415,8 +415,8 @@ X_FRAME_OPTIONS = 'SAMEORIGIN'
USE_X_FORWARDED_HOST = False
USE_X_FORWARDED_PORT = False
-# The Python dotted path to the WSGI application that Django's internal server
-# (runserver) will use. If `None`, the return value of
+# The Python dotted path to the WSGI application that Django's internal servers
+# (runserver, runfcgi) will use. If `None`, the return value of
# 'django.core.wsgi.get_wsgi_application' is used, thus preserving the same
# behavior as previous versions of Django. Otherwise this should point to an
# actual WSGI application object.
diff --git a/django/core/management/__init__.py b/django/core/management/__init__.py
index 739dc25..2aa84d7 100644
--- a/django/core/management/__init__.py
+++ b/django/core/management/__init__.py
@@ -251,8 +251,13 @@ class ManagementUtility(object):
# special case: the 'help' subcommand has no options
elif cwords[0] in subcommands and cwords[0] != 'help':
subcommand_cls = self.fetch_command(cwords[0])
+ # special case: 'runfcgi' stores additional options as
+ # 'key=value' pairs
+ if cwords[0] == 'runfcgi':
+ from django.core.servers.fastcgi import FASTCGI_OPTIONS
+ options.extend((k, 1) for k in FASTCGI_OPTIONS)
# special case: add the names of installed apps to options
- if cwords[0] in ('dumpdata', 'sqlmigrate', 'sqlsequencereset', 'test'):
+ elif cwords[0] in ('dumpdata', 'sqlmigrate', 'sqlsequencereset', 'test'):
try:
app_configs = apps.get_app_configs()
# Get the last part of the dotted path as the app name.
diff --git a/django/core/management/commands/runfcgi.py b/django/core/management/commands/runfcgi.py
new file mode 100644
index 0000000..98de800
--- /dev/null
+++ b/django/core/management/commands/runfcgi.py
@@ -0,0 +1,32 @@
+import argparse
+import warnings
+
+from django.core.management.base import BaseCommand
+from django.utils.deprecation import RemovedInDjango19Warning
+
+
+class Command(BaseCommand):
+ help = "Runs this project as a FastCGI application. Requires flup."
+
+ def add_arguments(self, parser):
+ parser.add_argument('args', nargs=argparse.REMAINDER,
+ help='Various KEY=val options.')
+
+ def handle(self, *args, **options):
+ warnings.warn(
+ "FastCGI support has been deprecated and will be removed in Django 1.9.",
+ RemovedInDjango19Warning)
+
+ from django.conf import settings
+ from django.utils import translation
+ # Activate the current language, because it won't get activated later.
+ try:
+ translation.activate(settings.LANGUAGE_CODE)
+ except AttributeError:
+ pass
+ from django.core.servers.fastcgi import runfastcgi
+ runfastcgi(args)
+
+ def usage(self, subcommand):
+ from django.core.servers.fastcgi import FASTCGI_HELP
+ return FASTCGI_HELP
diff --git a/django/core/servers/basehttp.py b/django/core/servers/basehttp.py
index 60fc09a..5560438 100644
--- a/django/core/servers/basehttp.py
+++ b/django/core/servers/basehttp.py
@@ -34,11 +34,13 @@ def get_internal_wsgi_application():
this will be the ``application`` object in ``projectname/wsgi.py``.
This function, and the ``WSGI_APPLICATION`` setting itself, are only useful
- for Django's internal server (runserver); external WSGI servers should just
- be configured to point to the correct application object directly.
+ for Django's internal servers (runserver, runfcgi); external WSGI servers
+ should just be configured to point to the correct application object
+ directly.
If settings.WSGI_APPLICATION is not set (is ``None``), we just return
whatever ``django.core.wsgi.get_wsgi_application`` returns.
+
"""
from django.conf import settings
app_path = getattr(settings, 'WSGI_APPLICATION')
diff --git a/django/core/servers/fastcgi.py b/django/core/servers/fastcgi.py
new file mode 100644
index 0000000..b44473b
--- /dev/null
+++ b/django/core/servers/fastcgi.py
@@ -0,0 +1,187 @@
+"""
+FastCGI (or SCGI, or AJP1.3 ...) server that implements the WSGI protocol.
+
+Uses the flup python package: http://www.saddi.com/software/flup/
+
+This is an adaptation of the flup package to add FastCGI server support
+to run Django apps from Web servers that support the FastCGI protocol.
+This module can be run standalone or from the django-admin / manage.py
+scripts using the "runfcgi" directive.
+
+Run with the extra option "help" for a list of additional options you can
+pass to this server.
+"""
+
+import importlib
+import os
+import sys
+
+__version__ = "0.1"
+__all__ = ["runfastcgi"]
+
+FASTCGI_OPTIONS = {
+ 'protocol': 'fcgi',
+ 'host': None,
+ 'port': None,
+ 'socket': None,
+ 'method': 'fork',
+ 'daemonize': None,
+ 'workdir': '/',
+ 'pidfile': None,
+ 'maxspare': 5,
+ 'minspare': 2,
+ 'maxchildren': 50,
+ 'maxrequests': 0,
+ 'debug': None,
+ 'outlog': None,
+ 'errlog': None,
+ 'umask': None,
+}
+
+FASTCGI_HELP = r"""
+ Run this project as a fastcgi (or some other protocol supported
+ by flup) application. To do this, the flup package from
+ http://www.saddi.com/software/flup/ is required.
+
+ runfcgi [options] [fcgi settings]
+
+Optional Fcgi settings: (setting=value)
+ protocol=PROTOCOL fcgi, scgi, ajp, ... (default %(protocol)s)
+ host=HOSTNAME hostname to listen on.
+ port=PORTNUM port to listen on.
+ socket=FILE UNIX socket to listen on.
+ method=IMPL prefork or threaded (default %(method)s).
+ maxrequests=NUMBER number of requests a child handles before it is
+ killed and a new child is forked (0 = no limit).
+ maxspare=NUMBER max number of spare processes / threads (default %(maxspare)s).
+ minspare=NUMBER min number of spare processes / threads (default %(minspare)s).
+ maxchildren=NUMBER hard limit number of processes / threads (default %(maxchildren)s).
+ daemonize=BOOL whether to detach from terminal.
+ pidfile=FILE write the spawned process-id to this file.
+ workdir=DIRECTORY change to this directory when daemonizing (default %(workdir)s).
+ debug=BOOL set to true to enable flup tracebacks.
+ outlog=FILE write stdout to this file.
+ errlog=FILE write stderr to this file.
+ umask=UMASK umask to use when daemonizing, in octal notation (default 022).
+
+Examples:
+ Run a "standard" fastcgi process on a file-descriptor
+ (for Web servers which spawn your processes for you)
+ $ manage.py runfcgi method=threaded
+
+ Run a scgi server on a TCP host/port
+ $ manage.py runfcgi protocol=scgi method=prefork host=127.0.0.1 port=8025
+
+ Run a fastcgi server on a UNIX domain socket (posix platforms only)
+ $ manage.py runfcgi method=prefork socket=/tmp/fcgi.sock
+
+ Run a fastCGI as a daemon and write the spawned PID in a file
+ $ manage.py runfcgi socket=/tmp/fcgi.sock method=prefork \
+ daemonize=true pidfile=/var/run/django-fcgi.pid
+
+""" % FASTCGI_OPTIONS
+
+
+def fastcgi_help(message=None):
+ print(FASTCGI_HELP)
+ if message:
+ print(message)
+ return False
+
+
+def runfastcgi(argset=[], **kwargs):
+ options = FASTCGI_OPTIONS.copy()
+ options.update(kwargs)
+ for x in argset:
+ if "=" in x:
+ k, v = x.split('=', 1)
+ else:
+ k, v = x, True
+ options[k.lower()] = v
+
+ if "help" in options:
+ return fastcgi_help()
+
+ try:
+ import flup # NOQA
+ except ImportError as e:
+ sys.stderr.write("ERROR: %s\n" % e)
+ sys.stderr.write(" Unable to load the flup package. In order to run django\n")
+ sys.stderr.write(" as a FastCGI application, you will need to get flup from\n")
+ sys.stderr.write(" http://www.saddi.com/software/flup/ If you've already\n")
+ sys.stderr.write(" installed flup, then make sure you have it in your PYTHONPATH.\n")
+ return False
+
+ flup_module = 'server.' + options['protocol']
+
+ if options['method'] in ('prefork', 'fork'):
+ wsgi_opts = {
+ 'maxSpare': int(options["maxspare"]),
+ 'minSpare': int(options["minspare"]),
+ 'maxChildren': int(options["maxchildren"]),
+ 'maxRequests': int(options["maxrequests"]),
+ }
+ flup_module += '_fork'
+ elif options['method'] in ('thread', 'threaded'):
+ wsgi_opts = {
+ 'maxSpare': int(options["maxspare"]),
+ 'minSpare': int(options["minspare"]),
+ 'maxThreads': int(options["maxchildren"]),
+ }
+ else:
+ return fastcgi_help("ERROR: Implementation must be one of prefork or "
+ "thread.")
+
+ wsgi_opts['debug'] = options['debug'] is not None
+
+ try:
+ module = importlib.import_module('.%s' % flup_module, 'flup')
+ WSGIServer = module.WSGIServer
+ except Exception:
+ print("Can't import flup." + flup_module)
+ return False
+
+ # Prep up and go
+ from django.core.servers.basehttp import get_internal_wsgi_application
+
+ if options["host"] and options["port"] and not options["socket"]:
+ wsgi_opts['bindAddress'] = (options["host"], int(options["port"]))
+ elif options["socket"] and not options["host"] and not options["port"]:
+ wsgi_opts['bindAddress'] = options["socket"]
+ elif not options["socket"] and not options["host"] and not options["port"]:
+ wsgi_opts['bindAddress'] = None
+ else:
+ return fastcgi_help("Invalid combination of host, port, socket.")
+
+ if options["daemonize"] is None:
+ # Default to daemonizing if we're running on a socket/named pipe.
+ daemonize = (wsgi_opts['bindAddress'] is not None)
+ else:
+ if options["daemonize"].lower() in ('true', 'yes', 't'):
+ daemonize = True
+ elif options["daemonize"].lower() in ('false', 'no', 'f'):
+ daemonize = False
+ else:
+ return fastcgi_help("ERROR: Invalid option for daemonize "
+ "parameter.")
+
+ daemon_kwargs = {}
+ if options['outlog']:
+ daemon_kwargs['out_log'] = options['outlog']
+ if options['errlog']:
+ daemon_kwargs['err_log'] = options['errlog']
+ if options['umask']:
+ daemon_kwargs['umask'] = int(options['umask'], 8)
+
+ if daemonize:
+ from django.utils.daemonize import become_daemon
+ become_daemon(our_home_dir=options["workdir"], **daemon_kwargs)
+
+ if options["pidfile"]:
+ with open(options["pidfile"], "w") as fp:
+ fp.write("%d\n" % os.getpid())
+
+ WSGIServer(get_internal_wsgi_application(), **wsgi_opts).run()
+
+if __name__ == '__main__':
+ runfastcgi(sys.argv[1:])
diff --git a/django/utils/daemonize.py b/django/utils/daemonize.py
new file mode 100644
index 0000000..76f4d5d
--- /dev/null
+++ b/django/utils/daemonize.py
@@ -0,0 +1,62 @@
+import os
+import sys
+
+from . import six
+
+buffering = int(six.PY3) # No unbuffered text I/O on Python 3 (#20815).
+
+if os.name == 'posix':
+ def become_daemon(our_home_dir='.', out_log='/dev/null',
+ err_log='/dev/null', umask=0o022):
+ "Robustly turn into a UNIX daemon, running in our_home_dir."
+ # First fork
+ try:
+ if os.fork() > 0:
+ sys.exit(0) # kill off parent
+ except OSError as e:
+ sys.stderr.write("fork #1 failed: (%d) %s\n" % (e.errno, e.strerror))
+ sys.exit(1)
+ os.setsid()
+ os.chdir(our_home_dir)
+ os.umask(umask)
+
+ # Second fork
+ try:
+ if os.fork() > 0:
+ os._exit(0)
+ except OSError as e:
+ sys.stderr.write("fork #2 failed: (%d) %s\n" % (e.errno, e.strerror))
+ os._exit(1)
+
+ si = open('/dev/null', 'r')
+ so = open(out_log, 'a+', buffering)
+ se = open(err_log, 'a+', buffering)
+ os.dup2(si.fileno(), sys.stdin.fileno())
+ os.dup2(so.fileno(), sys.stdout.fileno())
+ os.dup2(se.fileno(), sys.stderr.fileno())
+ # Set custom file descriptors so that they get proper buffering.
+ sys.stdout, sys.stderr = so, se
+else:
+ def become_daemon(our_home_dir='.', out_log=None, err_log=None, umask=0o022):
+ """
+ If we're not running under a POSIX system, just simulate the daemon
+ mode by doing redirections and directory changing.
+ """
+ os.chdir(our_home_dir)
+ os.umask(umask)
+ sys.stdin.close()
+ sys.stdout.close()
+ sys.stderr.close()
+ if err_log:
+ sys.stderr = open(err_log, 'a', buffering)
+ else:
+ sys.stderr = NullDevice()
+ if out_log:
+ sys.stdout = open(out_log, 'a', buffering)
+ else:
+ sys.stdout = NullDevice()
+
+ class NullDevice:
+ "A writeable object that writes to nowhere -- like /dev/null."
+ def write(self, s):
+ pass
我在 Hostgator 上看到可以在他们的托管服务上安装 Django,我已经联系了实时支持并回复说他们对此无能为力。
有人做过吗?
基本步骤是您需要 VPS 托管,http://www.hostgator.com/vps-hosting,除非他们已经为您完成,否则您将无法在他们的正常托管平台上安装 Django .
设置 VPS 后,您将拥有 SSH 凭据以登录到 Linux 主机。 (你应该在 Windows 上为此使用 PuTTY)。通过 SSH 连接到服务器后,您可以按照 Django 教程 (https://docs.djangoproject.com/en/1.8/intro/install/) 中的说明安装 Django。 (及其依赖项)
可以在 Windows 上开发 Django 应用程序,但比在 linux 主机上开发更难。这是一个意见。
HostGator 上的 Django 共享是可能的。这有点棘手,因为 Django 放弃了对 FastCGI 的支持。
使用 HostGator 自己的说明来设置 Django。 http://support.hostgator.com/articles/django-with-fastcgi#shared-reseller
但在此之前 运行 您需要将对 FastCGI 的支持修补回 Django。
- 幸运的是,Django 在一次提交中删除了所有 FastCGI: https://github.com/django/django/commit/41f0d3d3bc8b0a6831530e1176c6415f9ba45b0b.patch
- 此补丁需要逆向移植以指向您拥有的版本。 这种需要检查 django 源项目并使用 git.
- 不要担心消除 docs 和 tests 子文件夹的冲突,因为无论如何都需要将它们排除在重新 FastCGI 化补丁之外。
- 为 HostGator 中安装的 Django 版本准备好补丁文件后,使用 git apply 将 FastCGI 支持重新注入到位于虚拟环境中的 Django 代码中
./mydjango/lib/python2.7/site-packages/django
- 最后是我为 Django 版本 1.10.1 得到的补丁文件。
- 使用 PyMySQL 而不是标准 mysql 库。 PyMySQL 是一个纯粹的 python mysql 客户端,因为 Host Gator 不提供 gcc。
- 安装库:
pip install PyMySQL
- Monkey 在 manage.py 和 index.fcgi 中通过在 #! python行:
- 安装库:
#monkey patch importing pymysql
try:
import pymysql
pymysql.install_as_MySQLdb()
except ImportError:
pass
#Re-fast-cgi-ification-patch
From 51278286d278568dfe89263cad624204c01fa065 Mon Sep 17 00:00:00 2001
From: Joshua
Date: Tue, 6 Sep 2016 18:19:20 -0400
Subject: django folder only</p>
Revert "Removed FastCGI support per deprecation timeline; refs #20766."
This reverts commit 41f0d3d3bc8b0a6831530e1176c6415f9ba45b0b.
# Conflicts:
# django/core/management/__init__.py
# docs/howto/deployment/wsgi/index.txt
# docs/man/django-admin.1
# docs/ref/django-admin.txt
# tests/.coveragerc
# Conflicts:
# docs/man/django-admin.1
# docs/ref/django-admin.txt
diff --git a/django/conf/global_settings.py b/django/conf/global_settings.py
index 576ff6b..8d1461f 100644
--- a/django/conf/global_settings.py
+++ b/django/conf/global_settings.py
@@ -415,8 +415,8 @@ X_FRAME_OPTIONS = 'SAMEORIGIN'
USE_X_FORWARDED_HOST = False
USE_X_FORWARDED_PORT = False
-# The Python dotted path to the WSGI application that Django's internal server
-# (runserver) will use. If `None`, the return value of
+# The Python dotted path to the WSGI application that Django's internal servers
+# (runserver, runfcgi) will use. If `None`, the return value of
# 'django.core.wsgi.get_wsgi_application' is used, thus preserving the same
# behavior as previous versions of Django. Otherwise this should point to an
# actual WSGI application object.
diff --git a/django/core/management/__init__.py b/django/core/management/__init__.py
index 739dc25..2aa84d7 100644
--- a/django/core/management/__init__.py
+++ b/django/core/management/__init__.py
@@ -251,8 +251,13 @@ class ManagementUtility(object):
# special case: the 'help' subcommand has no options
elif cwords[0] in subcommands and cwords[0] != 'help':
subcommand_cls = self.fetch_command(cwords[0])
+ # special case: 'runfcgi' stores additional options as
+ # 'key=value' pairs
+ if cwords[0] == 'runfcgi':
+ from django.core.servers.fastcgi import FASTCGI_OPTIONS
+ options.extend((k, 1) for k in FASTCGI_OPTIONS)
# special case: add the names of installed apps to options
- if cwords[0] in ('dumpdata', 'sqlmigrate', 'sqlsequencereset', 'test'):
+ elif cwords[0] in ('dumpdata', 'sqlmigrate', 'sqlsequencereset', 'test'):
try:
app_configs = apps.get_app_configs()
# Get the last part of the dotted path as the app name.
diff --git a/django/core/management/commands/runfcgi.py b/django/core/management/commands/runfcgi.py
new file mode 100644
index 0000000..98de800
--- /dev/null
+++ b/django/core/management/commands/runfcgi.py
@@ -0,0 +1,32 @@
+import argparse
+import warnings
+
+from django.core.management.base import BaseCommand
+from django.utils.deprecation import RemovedInDjango19Warning
+
+
+class Command(BaseCommand):
+ help = "Runs this project as a FastCGI application. Requires flup."
+
+ def add_arguments(self, parser):
+ parser.add_argument('args', nargs=argparse.REMAINDER,
+ help='Various KEY=val options.')
+
+ def handle(self, *args, **options):
+ warnings.warn(
+ "FastCGI support has been deprecated and will be removed in Django 1.9.",
+ RemovedInDjango19Warning)
+
+ from django.conf import settings
+ from django.utils import translation
+ # Activate the current language, because it won't get activated later.
+ try:
+ translation.activate(settings.LANGUAGE_CODE)
+ except AttributeError:
+ pass
+ from django.core.servers.fastcgi import runfastcgi
+ runfastcgi(args)
+
+ def usage(self, subcommand):
+ from django.core.servers.fastcgi import FASTCGI_HELP
+ return FASTCGI_HELP
diff --git a/django/core/servers/basehttp.py b/django/core/servers/basehttp.py
index 60fc09a..5560438 100644
--- a/django/core/servers/basehttp.py
+++ b/django/core/servers/basehttp.py
@@ -34,11 +34,13 @@ def get_internal_wsgi_application():
this will be the ``application`` object in ``projectname/wsgi.py``.
This function, and the ``WSGI_APPLICATION`` setting itself, are only useful
- for Django's internal server (runserver); external WSGI servers should just
- be configured to point to the correct application object directly.
+ for Django's internal servers (runserver, runfcgi); external WSGI servers
+ should just be configured to point to the correct application object
+ directly.
If settings.WSGI_APPLICATION is not set (is ``None``), we just return
whatever ``django.core.wsgi.get_wsgi_application`` returns.
+
"""
from django.conf import settings
app_path = getattr(settings, 'WSGI_APPLICATION')
diff --git a/django/core/servers/fastcgi.py b/django/core/servers/fastcgi.py
new file mode 100644
index 0000000..b44473b
--- /dev/null
+++ b/django/core/servers/fastcgi.py
@@ -0,0 +1,187 @@
+"""
+FastCGI (or SCGI, or AJP1.3 ...) server that implements the WSGI protocol.
+
+Uses the flup python package: http://www.saddi.com/software/flup/
+
+This is an adaptation of the flup package to add FastCGI server support
+to run Django apps from Web servers that support the FastCGI protocol.
+This module can be run standalone or from the django-admin / manage.py
+scripts using the "runfcgi" directive.
+
+Run with the extra option "help" for a list of additional options you can
+pass to this server.
+"""
+
+import importlib
+import os
+import sys
+
+__version__ = "0.1"
+__all__ = ["runfastcgi"]
+
+FASTCGI_OPTIONS = {
+ 'protocol': 'fcgi',
+ 'host': None,
+ 'port': None,
+ 'socket': None,
+ 'method': 'fork',
+ 'daemonize': None,
+ 'workdir': '/',
+ 'pidfile': None,
+ 'maxspare': 5,
+ 'minspare': 2,
+ 'maxchildren': 50,
+ 'maxrequests': 0,
+ 'debug': None,
+ 'outlog': None,
+ 'errlog': None,
+ 'umask': None,
+}
+
+FASTCGI_HELP = r"""
+ Run this project as a fastcgi (or some other protocol supported
+ by flup) application. To do this, the flup package from
+ http://www.saddi.com/software/flup/ is required.
+
+ runfcgi [options] [fcgi settings]
+
+Optional Fcgi settings: (setting=value)
+ protocol=PROTOCOL fcgi, scgi, ajp, ... (default %(protocol)s)
+ host=HOSTNAME hostname to listen on.
+ port=PORTNUM port to listen on.
+ socket=FILE UNIX socket to listen on.
+ method=IMPL prefork or threaded (default %(method)s).
+ maxrequests=NUMBER number of requests a child handles before it is
+ killed and a new child is forked (0 = no limit).
+ maxspare=NUMBER max number of spare processes / threads (default %(maxspare)s).
+ minspare=NUMBER min number of spare processes / threads (default %(minspare)s).
+ maxchildren=NUMBER hard limit number of processes / threads (default %(maxchildren)s).
+ daemonize=BOOL whether to detach from terminal.
+ pidfile=FILE write the spawned process-id to this file.
+ workdir=DIRECTORY change to this directory when daemonizing (default %(workdir)s).
+ debug=BOOL set to true to enable flup tracebacks.
+ outlog=FILE write stdout to this file.
+ errlog=FILE write stderr to this file.
+ umask=UMASK umask to use when daemonizing, in octal notation (default 022).
+
+Examples:
+ Run a "standard" fastcgi process on a file-descriptor
+ (for Web servers which spawn your processes for you)
+ $ manage.py runfcgi method=threaded
+
+ Run a scgi server on a TCP host/port
+ $ manage.py runfcgi protocol=scgi method=prefork host=127.0.0.1 port=8025
+
+ Run a fastcgi server on a UNIX domain socket (posix platforms only)
+ $ manage.py runfcgi method=prefork socket=/tmp/fcgi.sock
+
+ Run a fastCGI as a daemon and write the spawned PID in a file
+ $ manage.py runfcgi socket=/tmp/fcgi.sock method=prefork \
+ daemonize=true pidfile=/var/run/django-fcgi.pid
+
+""" % FASTCGI_OPTIONS
+
+
+def fastcgi_help(message=None):
+ print(FASTCGI_HELP)
+ if message:
+ print(message)
+ return False
+
+
+def runfastcgi(argset=[], **kwargs):
+ options = FASTCGI_OPTIONS.copy()
+ options.update(kwargs)
+ for x in argset:
+ if "=" in x:
+ k, v = x.split('=', 1)
+ else:
+ k, v = x, True
+ options[k.lower()] = v
+
+ if "help" in options:
+ return fastcgi_help()
+
+ try:
+ import flup # NOQA
+ except ImportError as e:
+ sys.stderr.write("ERROR: %s\n" % e)
+ sys.stderr.write(" Unable to load the flup package. In order to run django\n")
+ sys.stderr.write(" as a FastCGI application, you will need to get flup from\n")
+ sys.stderr.write(" http://www.saddi.com/software/flup/ If you've already\n")
+ sys.stderr.write(" installed flup, then make sure you have it in your PYTHONPATH.\n")
+ return False
+
+ flup_module = 'server.' + options['protocol']
+
+ if options['method'] in ('prefork', 'fork'):
+ wsgi_opts = {
+ 'maxSpare': int(options["maxspare"]),
+ 'minSpare': int(options["minspare"]),
+ 'maxChildren': int(options["maxchildren"]),
+ 'maxRequests': int(options["maxrequests"]),
+ }
+ flup_module += '_fork'
+ elif options['method'] in ('thread', 'threaded'):
+ wsgi_opts = {
+ 'maxSpare': int(options["maxspare"]),
+ 'minSpare': int(options["minspare"]),
+ 'maxThreads': int(options["maxchildren"]),
+ }
+ else:
+ return fastcgi_help("ERROR: Implementation must be one of prefork or "
+ "thread.")
+
+ wsgi_opts['debug'] = options['debug'] is not None
+
+ try:
+ module = importlib.import_module('.%s' % flup_module, 'flup')
+ WSGIServer = module.WSGIServer
+ except Exception:
+ print("Can't import flup." + flup_module)
+ return False
+
+ # Prep up and go
+ from django.core.servers.basehttp import get_internal_wsgi_application
+
+ if options["host"] and options["port"] and not options["socket"]:
+ wsgi_opts['bindAddress'] = (options["host"], int(options["port"]))
+ elif options["socket"] and not options["host"] and not options["port"]:
+ wsgi_opts['bindAddress'] = options["socket"]
+ elif not options["socket"] and not options["host"] and not options["port"]:
+ wsgi_opts['bindAddress'] = None
+ else:
+ return fastcgi_help("Invalid combination of host, port, socket.")
+
+ if options["daemonize"] is None:
+ # Default to daemonizing if we're running on a socket/named pipe.
+ daemonize = (wsgi_opts['bindAddress'] is not None)
+ else:
+ if options["daemonize"].lower() in ('true', 'yes', 't'):
+ daemonize = True
+ elif options["daemonize"].lower() in ('false', 'no', 'f'):
+ daemonize = False
+ else:
+ return fastcgi_help("ERROR: Invalid option for daemonize "
+ "parameter.")
+
+ daemon_kwargs = {}
+ if options['outlog']:
+ daemon_kwargs['out_log'] = options['outlog']
+ if options['errlog']:
+ daemon_kwargs['err_log'] = options['errlog']
+ if options['umask']:
+ daemon_kwargs['umask'] = int(options['umask'], 8)
+
+ if daemonize:
+ from django.utils.daemonize import become_daemon
+ become_daemon(our_home_dir=options["workdir"], **daemon_kwargs)
+
+ if options["pidfile"]:
+ with open(options["pidfile"], "w") as fp:
+ fp.write("%d\n" % os.getpid())
+
+ WSGIServer(get_internal_wsgi_application(), **wsgi_opts).run()
+
+if __name__ == '__main__':
+ runfastcgi(sys.argv[1:])
diff --git a/django/utils/daemonize.py b/django/utils/daemonize.py
new file mode 100644
index 0000000..76f4d5d
--- /dev/null
+++ b/django/utils/daemonize.py
@@ -0,0 +1,62 @@
+import os
+import sys
+
+from . import six
+
+buffering = int(six.PY3) # No unbuffered text I/O on Python 3 (#20815).
+
+if os.name == 'posix':
+ def become_daemon(our_home_dir='.', out_log='/dev/null',
+ err_log='/dev/null', umask=0o022):
+ "Robustly turn into a UNIX daemon, running in our_home_dir."
+ # First fork
+ try:
+ if os.fork() > 0:
+ sys.exit(0) # kill off parent
+ except OSError as e:
+ sys.stderr.write("fork #1 failed: (%d) %s\n" % (e.errno, e.strerror))
+ sys.exit(1)
+ os.setsid()
+ os.chdir(our_home_dir)
+ os.umask(umask)
+
+ # Second fork
+ try:
+ if os.fork() > 0:
+ os._exit(0)
+ except OSError as e:
+ sys.stderr.write("fork #2 failed: (%d) %s\n" % (e.errno, e.strerror))
+ os._exit(1)
+
+ si = open('/dev/null', 'r')
+ so = open(out_log, 'a+', buffering)
+ se = open(err_log, 'a+', buffering)
+ os.dup2(si.fileno(), sys.stdin.fileno())
+ os.dup2(so.fileno(), sys.stdout.fileno())
+ os.dup2(se.fileno(), sys.stderr.fileno())
+ # Set custom file descriptors so that they get proper buffering.
+ sys.stdout, sys.stderr = so, se
+else:
+ def become_daemon(our_home_dir='.', out_log=None, err_log=None, umask=0o022):
+ """
+ If we're not running under a POSIX system, just simulate the daemon
+ mode by doing redirections and directory changing.
+ """
+ os.chdir(our_home_dir)
+ os.umask(umask)
+ sys.stdin.close()
+ sys.stdout.close()
+ sys.stderr.close()
+ if err_log:
+ sys.stderr = open(err_log, 'a', buffering)
+ else:
+ sys.stderr = NullDevice()
+ if out_log:
+ sys.stdout = open(out_log, 'a', buffering)
+ else:
+ sys.stdout = NullDevice()
+
+ class NullDevice:
+ "A writeable object that writes to nowhere -- like /dev/null."
+ def write(self, s):
+ pass