基于django的博客(1)

本文总阅读量

前记

一开始为了熟悉django而按照教程或者文章写的基于django的博客

一个非常简单的博客实现

github

代码仓

基本功能

代码量比较少只是简单的实现增删改

  • 管理员发表文章
  • 访问者查看文章
    • 归档
    • 标签
    • 分类
    • 搜索

new

DetailView与ListView

为了减少代码使用量等,在django中可以使用基于view来编写视图。常用的有DetailView与ListView,他们有些细微的却别:

  • 主要功能
    • ListView-从数据库中获取模型列表的数据
    • DetailView从数据库获取模型的一条记录数据。比如查看某篇文章的详情,就是从数据库中获取这篇文章的记录然后渲染模板。

方法:

  • DetailView 有以下方法:

    • dispatch()
    • http_method_not_allowed()
    • get_template_names()
    • get_slug_field()
    • get_queryset()
    • get_object()
    • get_context_object_name()
    • get_context_data()
    • get()
    • render_to_response()
  • ListView 有以下方法:

    • dispatch()
    • http_method_not_allowed()
    • get_template_names()
    • get_queryset()
    • get_context_object_name()
    • get_context_data()
    • get()
    • render_to_response()

内部结构:
ListView类图
ListView类图
DetailView类图
DetailView类图
在这两个类图中,最关键的组件就是MultiObjectMixin和SingleObjectMixin这两个类了,他们实现的功能是从数据库中读取数据,并且构建要传入template的context。每个类都有一些属性和方法可以覆盖,实现自定制,比如可以覆盖context_object_name变量,用来指定传入template的context的对象的变量名;可以覆盖get_context_data()方法,用来将其他的变量放到context中;为queryset赋值,就可以自己指定这个View操作的对象(列表);或者是直接重写get_queryset()/get_object()方法,简单暴力。

注意,这两个类,也是继承自TemplateResponseMixin,也就是说它们也是直接返回的TemplateResponse对象。

django的处理流程

浏览器访问流程

web server

django拥有一个自己的web server-runserver,主要用于开发和调试中,部署到线上环境时用的都是别的web server 如:nginx+uwsgi

runserver运行时主要是完成以下两件事:

  1. 解析参数,并通过django.core.servers.basehttp.get_internal_wsgi_application方法获取wsgi handler;
  2. 根据ip_address和port生成一个WSGIServer对象,接受用户请求
    get_internal_wsgi_application的源码如下:

image

通过上面的代码可知道,Django会先根据settings中的WSGI_APPLICATION来获取handler;
在创建project的时候,Django会默认创建一个wsgi.py文件,而settings中的WSGI_APPLICATION配置也会默认指向这个文件。看一下这个wsgi.py文件,其实它也和上面的逻辑一样,最终调用get_wsgi_application实现。

django http请求处理流程(来源于网上)

Django的具体处理流程大致如下:

  1. 加载settings.py

    在通过django-admin.py创建project的时候,Django会自动生成默认的settings文件和manager.py等文件,在创建WSGIServer之前会执行下面的引用:

    1
    from django.conf import settings

    上面引用在执行时,会读取os.environ中的DJANGO_SETTINGS_MODULE配置,加载项目配置文件,生成settings对象。所以,在manager.py文件中你可以看到,在获取WSGIServer之前,会先将project的settings路径加到os路径中。

  2. 创建WSGIServer

不管是使用哪个web server运行Django项目,在启动时都会调用django.core.servers.basehttp中的run()方法
创建一个django.core.servers.basehttp.WSGIServer类的实例,之后调用其serve_forever()方法启动HTTP服务。
run方法的源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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)
if threading:
# ThreadingMixIn.daemon_threads indicates how threads will behave on an
# abrupt shutdown; like quitting the server by the user or restarting
# by the auto-reloader. True means the server will not wait for thread
# termination before it quits. This will make auto-reloader faster
# and will prevent the need to kill the server manually if a thread
# isn't terminating correctly.
httpd.daemon_threads = True
httpd.set_app(wsgi_handler)
httpd.serve_forever()

如上,我们可以看到:在创建WSGIServer实例的时候会指定HTTP请求的Handler,
上述代码使用WSGIRequestHandler。当用户的HTTP请求到达服务器时,
WSGIServer会创建WSGIRequestHandler实例,使用其handler方法来处理HTTP请求(其实最终是调用wsgiref.handlers.BaseHandler中的run方法处理)。
WSGIServer通过set_app方法设置一个可调用(callable)的对象作为application,上面提到的handler方法最终会调用设置的application处理request,并返回response。
其中,WSGIServer继承自wsgiref.simple_server.WSGIServer,而WSGIRequestHandler继承自wsgiref.simple_server.WSGIRequestHandler,wsgiref是python标准库给出的WSGI的参考实现。其源码可自行到wsgiref参看,这里不再细说。

  1. 处理Request

第二步中说到的application,在Django中一般是django.core.handlers.wsgi.WSGIHandler对象,WSGIHandler继承自django.core.handlers.base.BaseHandler,这个是Django处理request的核心逻辑,它会创建一个WSGIRequest实例,而WSGIRequest是从http.HttpRequest继承而来

  1. 返回Response

上面提到的BaseHandler中有个get_response方法,该方法会先加载Django项目的ROOT_URLCONF,然后根据url规则找到对应的view方法(类),view逻辑会根据request实例生成并返回具体的response。
在Django返回结果之后,第二步中提到wsgiref.handlers.BaseHandler.run方法会调用finish_response结束请求,并将内容返回给用户

Django处理Request的流程

1.用户通过浏览器输入url请求一个页面
2.请求到达Request Middlewares,中间件对request做一些预处理或者直接response请求(处理包括ip判断用户判断等)
3.URLConf通过urls.py文件和请求的URL的对比,找到相应的View
4.View Middlewares被访问,同样可以对request做一些处理或者直接返回response
5.调用View中的函数,进行逻辑判断
6.如果需要访问数据库获取或修改数据时,则通过Models访问底层的数据
7.view把对应的数据生成一个字典并返回给Template
8.Template接受数据并生成页面
8.1Template使用Filters和Tags去渲染输出
8.2HTTPResponse被发送到Response Middlewares
8.3任何Response Middlewares都可以丰富response或者返回一个完全不同的response
8.4Response返回到浏览器,呈现给用户

Middleware(中间件)

Middleware是在Django BaseHandler的load_middleware方法执行时加载的,加载之后会建立四个列表作为处理器的实例变量:

_request_middleware:process_request方法的列表
_view_middleware:process_view方法的列表
_response_middleware:process_response方法的列表
_exception_middleware:process_exception方法的列表

Django的中间件是在其配置文件(settings.py)的MIDDLEWARE_CLASSES元组中定义的。在MIDDLEWARE_CLASSES中,中间件组件用字符串表示:指向中间件类名的完整python路径。例如

1
2
3
4
5
6
7
8
9
10
`MIDDLEWARE_CLASSES = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]`

中间件出现的顺序非常重要:在request和view的处理阶段,Django按照MIDDLEWARE_CLASSES中出现的顺序来应用中间件,而在response和exception异常处理阶段,Django则按逆序来调用它们。也就是说,Django将MIDDLEWARE_CLASSES视为view函数外层的顺序包装子:在request阶段按顺序从上到下穿过,而在response则反过来。

URLConf

URLConf相当于Django使用的地图告诉django要怎么去寻找url
第一个参数是url,可以通过正则去比对相应的url。
第二个参数是view,告诉Django如果这个url对应的view

ps:第二个参数也可以是url把匹配到的url导向另一个app下面的url。使得url不会集成于一页,同时可以把二级url区分开

第三个参数是命名空间,告诉那些需要调用url的(如模板),输入这个命名空间的名称就能获取到对应的url

Template

django通过模板把动态数据导入html文件并返回给用户,需要注意的是,模板里不能编写python代码

部署

部署教程

查看评论