Learning Django: the hard way (1)
Learning Django: the hard way (1)
What does "runserver" do?
Django provides a light-weight web server for development and test use. You can just start it using the command something like this-
python manage.py runserver 0.0.0.0:8000
manage.py just calls -
django.core.management.execute_from_command_line(sys.argv)
OK, so we need to dig into it a little to bit to see where the runserver comes into play. Finally, it turns out the parameter "runserver" would create a new instance of Command from the module django.core.management.commands.runserver.py.
There is one method to dynamically load the command class based on the command parameter, like runserver. The code is like this -
def load_command_class(app_name, name):
"""
Given a command name and an application name, returns the Command
class instance. All errors raised by the import process
(ImportError, AttributeError) are allowed to propagate.
"""
module = import_module('%s.management.commands.%s' % (app_name, name))
return module.Command()
OK, so far the corresponding command object of runserver has been created. Next, the method handle of the command object is called which in turns would call the method inner_run -
def inner_run(self, *args, **options):
from django.conf import settings
from django.utils import translation
threading = options.get('use_threading')
shutdown_message = options.get('shutdown_message', '')
quit_command = 'CTRL-BREAK' if sys.platform == 'win32' else 'CONTROL-C'
self.stdout.write("Performing system checks...\n\n")
self.validate(display_num_errors=True)
try:
self.check_migrations()
except ImproperlyConfigured:
pass
now = datetime.now().strftime('%B %d, %Y - %X')
if six.PY2:
now = now.decode(get_system_encoding())
self.stdout.write((
"%(started_at)s\n"
"Django version %(version)s, using settings %(settings)r\n"
"Starting development server at http://%(addr)s:%(port)s/\n"
"Quit the server with %(quit_command)s.\n"
) % {
"started_at": now,
"version": self.get_version(),
"settings": settings.SETTINGS_MODULE,
"addr": '[%s]' % self.addr if self._raw_ipv6 else self.addr,
"port": self.port,
"quit_command": quit_command,
})
# django.core.management.base forces the locale to en-us. We should
# set it up correctly for the first request (particularly important
# in the "--noreload" case).
translation.activate(settings.LANGUAGE_CODE)
try:
handler = self.get_handler(*args, **options)
run(self.addr, int(self.port), handler,
ipv6=self.use_ipv6, threading=threading)
except socket.error as e:
# Use helpful error messages instead of ugly tracebacks.
ERRORS = {
errno.EACCES: "You don't have permission to access that port.",
errno.EADDRINUSE: "That port is already in use.",
errno.EADDRNOTAVAIL: "That IP address can't be assigned-to.",
}
try:
error_text = ERRORS[e.errno]
except KeyError:
error_text = str(e)
self.stderr.write("Error: %s" % error_text)
# Need to use an OS exit because sys.exit doesn't work in a thread
os._exit(1)
except KeyboardInterrupt:
if shutdown_message:
self.stdout.write(shutdown_message)
sys.exit(0)
The meat and potatoes of this code is the following two lines -
handler = self.get_handler(*args, **options)
run(self.addr, int(self.port), handler, ipv6=self.use_ipv6, threading=threading)
Before looking into the code, it's better to have a review about PEP333 (WSGI), or just take a look at here
What are the two roles played by Django?
Django, itself, is a web framwork which complies with WSGI. From the framework side, it should provides one application handler(callable) wich takes in two parameters: environ and start_response. At the same time, as Django also provides one web server, it needs to provide a mechnisam to invoke the application handler(callable) for each request it receives from an Http client.
OK, after understanding these two roles can we move on to look at the code mentioned above.
How the application and web server interact?
First, let's focus on the application handler.
handler = self.get_handler(*args, **options)
The handler is the one either we configured in Django settings.py or by calling "get_wsgi_application()", seen from the method get_internal_wsgi_application() which is called by get_handler()
Note Django project will create an application by default, and it's also created by calling
"get_wsgi_application()"
In "settings.py" -
WSGI_APPLICATION = '.wsgi.application'
In "wsgi.py":
from django.core.wsgi import get_wsgi_application
application = get_wsgi_application()
def get_internal_wsgi_application():
"""
Loads and returns the WSGI application as configured by the user in
``settings.WSGI_APPLICATION``. With the default ``startproject`` layout,
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 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')
if app_path is None:
return get_wsgi_application()
try:
return import_string(app_path)
except ImportError as e:
msg = (
"WSGI application '%(app_path)s' could not be loaded; "
"Error importing module: '%(exception)s'" % ({
'app_path': app_path,
'exception': e,
})
)
six.reraise(ImproperlyConfigured, ImproperlyConfigured(msg),
sys.exc_info()[2])
Let's continue looking at function get_wsgi_application() -
def get_wsgi_application():
"""
The public interface to Django's WSGI support. Should return a WSGI
callable.
Allows us to avoid making django.core.handlers.WSGIHandler public API, in
case the internal WSGI implementation changes or moves in the future.
"""
django.setup()
return WSGIHandler()
Please note the specification of WSGIHandler does comply with PEP333: take in "environ" and "start_response".
class WSGIHandler(base.BaseHandler):
initLock = Lock()
request_class = WSGIRequest
def __call__(self, environ, start_response):
# Set up middleware if needed. We couldn't do this earlier, because
# settings weren't available.
if self._request_middleware is None:
with self.initLock:
try:
# Check that middleware is still uninitialized.
if self._request_middleware is None:
self.load_middleware()
except:
# Unload whatever middleware we got
self._request_middleware = None
raise
set_script_prefix(get_script_name(environ))
signals.request_started.send(sender=self.__class__)
try:
request = self.request_class(environ)
except UnicodeDecodeError:
logger.warning('Bad Request (UnicodeDecodeError)',
exc_info=sys.exc_info(),
extra={
'status_code': 400,
}
)
response = http.HttpResponseBadRequest()
else:
response = self.get_response(request)
response._handler_class = self.__class__
status = '%s %s' % (response.status_code, response.reason_phrase)
response_headers = [(str(k), str(v)) for k, v in response.items()]
for c in response.cookies.values():
response_headers.append((str('Set-Cookie'), str(c.output(header=''))))
start_response(force_str(status), response_headers)
return response
So far, we have figure out the application handler. Now let's turn to web server and see the function "run" in the module "django.core.servers.basehttp.py".
def run(addr, port, wsgi_handler, ipv6=False, threading=False):
server_address = (addr, port)
if threading:
httpd_cls = type(str('WSGIServer'), (socketserver.ThreadingMixIn, WSGIServer), {})
else:
httpd_cls = WSGIServer
httpd = httpd_cls(server_address, WSGIRequestHandler, ipv6=ipv6)
httpd.set_app(wsgi_handler)
httpd.serve_forever()
Here it will create a WSGIServer object, please note that the server will have a "WSGIRequestHandler" and also take into account wsgi appliation (wsgi_handler) just created.
Note: Django WSGIServer inherited from python provided "WSGIServer" - WSGIServer from the module
"simple_server.py" which can be found in the folder "/Lib/wsgiref/"
"WSGIRequestHandler" also inherited from python provided "WSGIRequestHandler", just like "WSGIServer"
WSGIRequestHandler has a method "run", which will do the real stuff. Please note this function specification also complies with PEP333, and it will call the WSGI application handler passing in the environ and start_response function.
def run(self, application):
"""Invoke the application"""
# Note to self: don't move the close()! Asynchronous servers shouldn't
# call close() from finish_response(), so if you close() anywhere but
# the double-error branch here, you'll break asynchronous servers by
# prematurely closing. Async servers must return from 'run()' without
# closing if there might still be output to iterate over.
try:
self.setup_environ()
self.result = application(self.environ, self.start_response)
self.finish_response()
except:
try:
self.handle_error()
except:
# If we get an error handling an error, just give up already!
self.close()
raise # ...and let the actual server figure it out.
Learning Django: the hard way (1)的更多相关文章
- Learning Django Resources
Learning Django Django makes it easier to build better Web apps more quickly and with less code. Web ...
- django-filter version 2.0 改动
今天使用django-filter时候遇到了下面这个问题: django-filter: TypeError at /goods/ init() got an unexpected keyword a ...
- Python Django Learning Notes..
The first time I came across django was last month.. Since then I was considering it as the better c ...
- 【Machine Learning】Python开发工具:Anaconda+Sublime
Python开发工具:Anaconda+Sublime 作者:白宁超 2016年12月23日21:24:51 摘要:随着机器学习和深度学习的热潮,各种图书层出不穷.然而多数是基础理论知识介绍,缺乏实现 ...
- Machine and Deep Learning with Python
Machine and Deep Learning with Python Education Tutorials and courses Supervised learning superstiti ...
- Django Web开发【1】Django简介
前言 看完<Django Book>之后, 总想找个实例来实战开发下,无奈国内Django的书籍相当少,只能从英文书籍中吸取养料,偶然之后得到Learning Website Develo ...
- 利用python web框架django实现py-faster-rcnn demo实例
操作系统.编程环境及其他: window7 cpu python2.7 pycharm5.0 django1.8x 说明:本blog是上一篇blog(http://www.cnblogs.co ...
- Django学习(2)数据宝库
数据库是一所大宝库,藏着各种宝贝.一个没有数据库的网站,功能有限.在Django中,支持的数据库有以下四种: SQLite3 MySQL PostgreSQL Oracle 其中SQLite3为Dja ...
- Django学习(4)表单,让数据库更美好
表单,在HTML中的标签为<form></form>,在网页中主要负责数据采集功能.我们在浏览网站时,常常会碰到注册账号.账号登录等,这就是表单的典型应用. 在Django学习 ...
随机推荐
- 如何快速去掉.svn文件夹?
我们在工程的协作开发过程中,常用的是 svn , 有时我们需要一个干净的 网站版本,没有 .svn 这些文件夹记录的版本传到服务器上使用,自己一个个去文件删除的话也太累了,这时我们就用到以下功能,用c ...
- Python编程-Office操作-操作Excel(上)
首先,需要安装openpyxl库 http://openpyxl.readthedocs.org/en/default/ pyton 2.xpip install openpyxl python 3. ...
- Android Bundle存储数据类型
曾经被问到这样一个问题:Bundle能存哪些数据类型,不能存哪些数据类型? 当时那个汗啊,因为,平常使用Bundle,要么使用基本数据类型,要么序列化自定义的Class,那到底能存哪些类型,不能存哪些 ...
- 学习Struts框架系列(三):声明式异常处理
在Struts1.X的版本中加入了对异常的处理Exception Handler,有了它我们可以不使用try/catch捕获异常,一旦出现了我们已经定义的异常,那么就会转到相应的页面,并且携带异常信息 ...
- 使用Draw rect 绘制圆角矩形
- (void)drawRect:(CGRect)rect { CGContextRef context = UIGraphicsGetCurrentContext(); UIGraphicsPush ...
- 【React Native开发】React Native控件之ListView组件解说以及最齐全实例(19)
),React Native技术交流4群(458982758).请不要反复加群!欢迎各位大牛,React Native技术爱好者加入交流!同一时候博客左側欢迎微信扫描关注订阅号,移动技术干货,精彩文章 ...
- 激活web容器对静态资源的默认servlet处理
在某些servlet的url匹配模式使用/时会拦截一些静态的资源的请求导致无法正确访问,可以采取web容器默认的servlet来处理,当然那些mvc一般也都提供了处理的方法,用何种方式可以自行决定,这 ...
- python之函数用法file()
# -*- coding: utf-8 -*- #python 27 #xiaodeng #python之函数用法file() #file() #说明:file()内建函数它的功能等于open(),但 ...
- centos 6.4 调整home和root分区大小
调整过程中可以随时查看硬盘分区情况,命令: lsblk df -h 压缩home分区到5G: [root@fscp-dev /]# df -h 文件系统 容量 已用 可用 已用%% 挂载点 /dev/ ...
- 彻底抛弃脚本录制,LR脚本之使用web_custom_request函数自定义http请求
初学性能测试时候,第一步必学脚本录制,但一路下来各种录制失败.回放脚本失败的问题层出不穷,究其原因一是LR本身存在对测试环境的兼容性问题导致录制失败,更深层次的原因是录制者不清楚LR录制脚本的原理,或 ...