github地址
https://github.com/0x55aa/pytoto
写不下去了,又开始写别的了 我去。
总是做着做着发现东西越来越多。
Read more...
Archive for django
django源码阅读,settings
在django/conf/__init__.py里,最后一行,settings = LazySettings()。到LazySettings(),继承自LazyObject,django/utils/functional.py里,初始化的时候self._wrapped为object()。LazyObject也设置了__getattr__,不过差不多。回头看LazySettings的__getattr__,开始要执行_setup,然后使用getattr取值。
----
def _setup(self, name=None):
settings_module = os.environ[ENVIRONMENT_VARIABLE],这个在wsgi脚本,或者在manage.py里有设置,就是项目的setting,例如mysite.settings。然后self._wrapped = Settings(settings_module)。Settings应该是设置值的。
----
Settings集成自BaseSettings,BaseSettings里只有一个__setattr__方法。看Settings的init方法,第一步导入global_settings,在同一个目录里,定义了全局的setting。导入使用dir获得所有变量名,判断变量名如果全为大写,就setattr。然后看BaseSettings,第一个判读"MEDIA_URL", "STATIC_URL",必须以’/‘结尾。然后判断ALLOWED_INCLUDE_ROOTS必须是str,然后就设置。
然后使用import_module()导入项目settings,py3带的这个功能。。。
然后后边类似的判断导入项目settings,其中"INSTALLED_APPS", "TEMPLATE_DIRS"必须是tuple,不能是str不然设置成tuple。必须有SECRET_KEY,设置TIME_ZONE。ok了,导入变量完毕了。
----
self._configure_logging()
settings里的日志设置,先不看了,以后再说。
Read more...
django源码阅读,urlconf
urlconf = settings.ROOT_URLCONF
urlresolvers.set_urlconf(urlconf)
resolver = urlresolvers.RegexURLResolver(r'^/', urlconf)
set_urlconf,如果没有设置urlconf的文件路径,保存;有,删掉。下边生成 resolver对象。
resolver_match = resolver.resolve(request.path_info)
callback, callback_args, callback_kwargs = resolver_match
request.resolver_match = resolver_match
找到RegexURLResolver里的resolve,match = self.regex.search(path)是匹配上边的 r'^/',也就是path_info必须是’/‘开头,如果不匹配直接404。然后,生成新地址为去掉’/‘剩下的。获得url_patterns,从rulconf得到urlconf_module,从urlconf_module得到urlpatterns,就是url配置文件里的变量。然后返回urlpatterns。
然后遍历urlpatterns,这里要先看一下urls.py里的三个函数了,patterns, include, url。
def include(arg, namespace=None, app_name=None):
判断arg为tuple的写法是:include((urlconf_module, app_name, namespace))并且不能有namespace参数。这种写法没用过
不是tuple,判断arg的类型为string,导入urls.py.然后不是string就是mudule了。然后都获取urls.py里定义的urlpatterns。然后下边验证了一下每一个规则的类型。返回数据。返回的数据和参数一样,当arg为tuple时就是返回arg。
def url(regex, view, kwargs=None, name=None, prefix='')
先判断view为 list或者tuple就是有include的时候,返回RegexURLResolver对象。
否则view是string,返回RegexURLPattern对象。
def patterns(prefix, *args):
还是先判断是否可以为list和tuple,如果是,调用url()。说明在urls.py里url完全可以不写。如果是RegexURLPattern,添加前缀。最后返回所有的regex。也就是说最终的urlpatterns就是一个包含所有RegexURLPattern的list。
上边在dist-packages/django/core/urlresolvers.py里RegexURLPattern里的resolve,for循环urlpatterns,然后用每一个regex对象的resolve方法去匹配新的地址。当是include的时候 对象还是RegexURLResolver,所以还是这个resolve,起到递归循环。当是RegexURLPattern时,如果匹配成功,返回一个ResolverMatch,arg或kwargs是匹配的url参数,再在后边又更新上url()配置里的参数。如果匹配到最后还没匹配到,404。
ResolverMatch有一个ResolverMatch方法,用在这句上,callback, callback_args, callback_kwargs = resolver_match
并且将返回的ResolverMatch存到request里。
url匹配完了
Read more...
django源码阅读,WSGIHandler里middleware,view流程
WSGIHandler继承自BaseHandler,BaseHandler初始化的时候_request_middleware和其他moddleware变量都设置为None。
在WSGIHandler中,先通过判断_request_middleware为None,执行load_middleware。
在load_middleware里根据在settings.MIDDLEWARE_CLASSES里的配置导入所有middleware,并判断class里边包含的方法,分别插入相应的middleware列表里。现在_request_middleware是一个列表。load_middleware结束
回到WSGIHandler,
set_script_prefix(base.get_script_name(environ)),get_script_name从environ得到SCRIPT_NAME,如果设置settings.FORCE_SCRIPT_NAME,回直接返回settings.FORCE_SCRIPT_NAME,默认为None。django竟然还提供这种碉堡的功能。。。set_script_prefix判断SCRIPT_NAME结尾是否是‘/’不是的话加上,并且在threading local里边保存SCRIPT_NAME。
signals.request_started.send(sender=self.__class__),用来调用绑定到request_started的方法,大体看了一下没看懂。
request = self.request_class(environ),得到request,初始化只是设置了一堆的变量。
response = self.get_response(request),,在get_response里得到urlconf,settings.ROOT_URLCONF就是配置url的入口文件。这里先不看了,以后分析。接着在一个大的try语句里,设置response为None,遍历_request_middleware,只要有response返回就停止。如果执行完response还是none,下边匹配url找到view,然后遍历执行_view_middleware,有response就停止。然后遍历完response还是none执行view。
response = wrapped_callback(request, *callback_args, **callback_kwargs)
如果抛出异常,遍历执行_exception_middleware,返回response不为None就停止,如果最后为None,raise再抛异常。看出exception_middleware只用来在用户写的view里边出现异常的处理。
如果执行完view,还是none,就会抛出The view didn't return an HttpResponse object.的异常。
在这里前边的midddleware,只要有response返回,就不会执行后边的,直接到执行下边了。因为在执行middleware的前边,都先判断response是none才执行。
最后,判断response可调用render,遍历执行_template_response_middleware,最后调用response.render()。这个大的try语句检测执行上边这些操作的404 403等各种异常。
最后遍历执行_response_middleware里的方法,然后调用apply_response_fixes,执行response_fixes里的所有方法修改response。response_fixes在BaseHandler开始定义好了。处理完后返回response。
回到了WSGIHandler,设置http返回的headers,然后直接返回response。
WSGIHandler整个看完了,现在要详细看的好多了。
url的解析部分。
setting middleware里django的默认设置都做了什么。
wrapped_callback调view也看一下。(make_view_atomic这里是数据库事务相关内容)
还有没看懂的signal,以前也没接触过。
Read more...
django源码阅读-reload代码自动重载
django在你执行python manage.py runserver的时候,在修改代码后会自动重启,研究一下是怎么实现的。
django/utils/autoreload.py
main(),我只看python_reloader,RUN_MAIN通过搜索源代码,发现只有在这个文件有两处,一个是下边else执行时设置为true。也就是说开始可能没有设置值,先执行restart_with_reloader()。精彩到了。。设置新的environ,RUN_MAIN为True。用os.spawnve启动新的reloader()进程,现在RUN_MAIN为True!然后在restart_with_reloader这个父进程里一直在等待判断子进程是否返回exit code,如果不是3就退出循环结束了。
在的reload进程执行new_thread(),也就是启动一个server。下边执行reloader_thread()
----
reloader_thread()里边
先执行ensure_echo_on(),先判断termios是否导入成功,termios是一个py模块,是unix平台的控制通信端口的,不怎么懂。如果模块没导入成功,将不做任何操作。如果导入成功,从字面意思就是确保echo打开。这不懂,也不是重点。
下边判断RUN_RELOADER,开始为True,进入循环,判断code_changed(),如果只要有一个文件改变code_changed就返回true。然后接着sys.exit(3)。每隔一秒判断一次。
如果py文件改变,执行了sys.exit(3),然后子进程就会结束。父进程在restart_with_reloader判断exit_code等于三,然后进行下一个while ture的循环。重新创建RUN_MAIN=True的子进程,重新创建一个server,等待(汗)代码修改 然后再退出,,,一直循环下去。
再说说exit_code不等与3的时候,比如子进程在启动server后,reloader_thread等待(再汗)代码改变的时候,你按了ctrl c,然后捕获KeyboardInterrupt异常,代码里什么都不做,然后子线程就会结束,这时exit_code不等于3,直接return exit_code结束了父进程,程序结束了。
Read more...
django源码阅读,python manage.py runserver
这次从头看起。
---
从项目的manage.py看,只有execute_from_command_line(sys.argv)这一个,sys.argv后边看到传不传一样。在django/core/management/__init__.py最后,ManagementUtility对象初始化,保存命令参数和项目路径。execute前边进行参数的解析,设置参数,最后一行 self.fetch_command(subcommand).run_from_argv(self.argv)
这个功能是执行相应的命令。
---
先看fetch_command(),里边get_commands,取得django自带的命令和用户项目写的命令,返回map{命令:app_name},django自带目录的是django/core/management/commands,app_name为django.core。还要过滤目录下的__init__.py。。。
下一步在fetch_command通过返回的字典获得app_name,下边就是根据app_name导入command。django通过判断app_name有没有BaseCommand来确定是否已经导入command模块(命令命名的py文件),如果没有导入,导入并返回里边的Command类就是定义的命令。最后返回Command类。
----
下边调用run_from_argv方法,这个Command类是集成BaseCommand,在django/core/management/__init__.py里边,先设置参数然后到execute里边。self.validate()model的定义检查等。然后执行了handler()就是命令的逻辑函数了。最后就是输出结果,有一个output_transaction,应该是操作数据库进行的操作,如查看数据表结构,后边看,看是数据库操作。
----
然后就是找到你想看的命令对应的文件看了。先看runserver了,其他先不看。
django/core/management/commands/runserver.py,handler(),先判断了DEBUG为false时,必须设置ALLOWED_HOSTS。然后ipv6的一坨,没看。
到了run(),只区分是否自动重载代码,不想自动加载要命令后边加上--noreload。然后只看自动重载的代码autoreload.main(self.inner_run, args, options),不过也要用到self.inner_run。。。
----
/django/utils/autoreload.py,main(),里边通过判断sys.platform开始字符串是‘java'选择使用哪个reloader。。没研究过jython,长知识。check_errors捕获执行inner_run时的异常。下边就是reload了,没看懂,等后边详细看看。
----
回到inner_run,开始打印了一堆提示信息。到get_handler里边返回get_internal_wsgi_application().
django/core/servers/basehttp.py,get_internal_wsgi_application,,判断settings里边是否设置WSGI_APPLICATION,默认设置,在项目里wsgi.py.
如果没设置,找get_wsgi_application,设置了导入wsgi.py,返回application,而application也是get_wsgi_application.
get_wsgi_application返回WSGIHandler(),/django/core/handlers/wsig.py,处理请求的逻辑在这里开始了。以后分析。
inner_run最后run(),WSGIServer继承自wsgiref.simple_server.WSGIServer。初始化传入,addr,wsgi_handler(刚刚返回的处理请求的逻辑!,后边用set_app设置),ipv6的。
-----
下边主要想看一下reload是怎么做的(纯属好奇)和WSGIHandle(最终目的!)
Read more...
一个小的微信应用
使用django写的微信应用,几个月前了,现在又看了一下。
当时想做一个宠物照片分享,信息查询的应用。现在发现微信应用不适合做这种功能这么全的,要依赖网页那样没意思了。接触微信多了也发现这个手机app也没什么意思,就用来做宣传什么的不错,再一个做个抽奖,定时发文章的那种应用比较适用。
用django写主要是操作数据库什么的也方便,其实就一个url请求,官方还有一套验证,不过如果url足够保密,不验证也无所谓。
然后解析xml,按照不同的动作做不同的事。已经实现的功能中,最大的一个是能够搜索宠物店或者宠物医院的。
数据来自百度地图,让同学帮忙抓的,直接用百度地图的开发api,抓取限制足够轻松的抓取完。
我用的结巴分词,分析的地址,店名数据,制作搜索词。用的whoosh检索。
这两个放在sae上时,不能创建文件,必须制定一个目录,由于店面不会长变,结巴分词的也不更新,所以我直接在项目下建的目录,然后本地生成,直接svn提交到sae上。whoosh是直接用api的很方便很爽,没有选择一些集成到django的插件,感觉配置什么的很麻烦也不爽,不如直接下载下代码放到项目目录下直接调用来的爽。
Read more...
django单元测试数据库设置
在settings里加入
Read more...
if 'test' in sys.argv:
DATABASES['default'] = {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': 'test_db'
}
回加快数据库的生成操作,用time试了一下,效果非常显著。我写了一个测试,从显示看创建数据库用了18秒,占了百分之九十九以上,当然这个比重没啥用。
每次都要在setUp()里边创建数据,然后再测试,不知道有没有好方法,可以在测试开始就创建一个完整数据库,并保证每一个测试类都能保持数据库数据的不变
使用django,nginx,supervisor,Gunicorn,virtualenv,mysql搭建网站
在工作时服务器上环境的搭建,做个笔记记录。用到的东西主要有:django,nginx,supervisor,Gunicorn,virtualenv,mysql。
安装就略过了,每一个的文档上有介绍。virtualenv有一个virtualenvwrapper方便操作。
先安装virtualenv,然后在python虚拟环境里边安装django,gunicorn等相关库。
supervisor用来守护django网站启动的进程,默认配置文件添加/etc/supervisor/conf.d/name.conf
Read more...
[program:code] command=/home/sys/.virtualenvs/%(program_name)s/bin/gunicorn %(program_name)s.wsgi:application -c /home/www/%(program_name)s/%(program_name)s/gunicorn.conf.py user=hg directory=/home/www/%(program_name)s autostart=true autorestart=true redirect_stderr=Truegunicorn.conf.py就是启动django的一些参数,制定监听的端口bind = "127.0.0.1:9006"。然后在nginx配置文件里边,进行转发。
server { listen 80; set $name "code"; server_name code.xx.com; root /home/www/${name}/root; access_log /var/log/nginx/${name}.access.log; location ~ (\.hg|\.orig|\.bak) { deny all; } location /static/ { expires max; access_log off; alias /home/www/${name}/static/; } location / { proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_redirect off; proxy_pass http://127.0.0.1:9006; } }supervisor的一些命令: 修改配置文件以后要使用supervisorctl update命令,否则不会更新。刚开始的时候,捣鼓了好长时间 才知道要这样搞0 0. supervisorctl start all启动所有进程, supervisorctl start code 单独启动code进程。 使用supervisorctl可以进入管理程序。
django1.6 RedirectView小改变
0 0,今天用到redirectview,查文档,发现在django1.6版本可以直接指定pattern_name参数来直接指定跳转的url,方便了好多0 0.以前很讨厌在url里引用一大堆东西,我都尽可能写在views里边,至少看起来清楚。
下面有介绍get_redirect_url()只有在url没有设置的时候才会用到pattern_name。doc:https://docs.djangoproject.com/en/1.6/ref/class-based-views/base/#redirectview
Read more...