django复习 以及源码

django请求生命周期

在浏览器上输入网址会发生什么事?
(地址会朝我对应的ip地址发送get请求,get请求遵循http协议)
先进入实现了wsgi协议的web服务器----》进入django---》中间件---》路由---》视图---》取模板,取数据,用数据渲染模板---》返回模板的字符串---》在浏览器上看到页面了
1 wsgi和cgi:通用网关协议
# 实现了wsgi协议的web服务器:uwsgi
# 对应到java中就是tomcat

最简单的Web应用就是先把HTML用文件保存好,用一个现成的HTTP服务器软件,接收用户请求,从文件中读取HTML,返回。

如果要动态生成HTML,就需要把上述步骤自己来实现。不过,接受HTTP请求、解析HTTP请求、发送HTTP响应都是苦力活,如果我们自己来写这些底层代码,还没开始写动态HTML呢,就得花个把月去读HTTP规范。

正确的做法是底层代码由专门的服务器软件实现,我们用Python专注于生成HTML文档。因为我们不希望接触到TCP连接、HTTP原始请求和响应格式,所以,需要一个统一的接口协议来实现这样的服务器软件,让我们专心用Python编写Web业务。这个接口就是WSGI:Web Server Gateway Interface。而wsgiref模块就是python基于wsgi协议开发的服务模块。

 1 from wsgiref.simple_server import make_server
 2 
 3 def mya(environ, start_response):
 4     print(environ)
 5     start_response('200 OK', [('Content-Type', 'text/html')])
 6     if environ.get('PATH_INFO') == '/index':
 7         with open('index.html','rb') as f:
 8             data=f.read()
 9 
10     elif environ.get('PATH_INFO') == '/login':
11         with open('login.html', 'rb') as f:
12             data = f.read()
13     else:
14         data=b'<h1>Hello, web!</h1>'
15     return [data]
16 
17 if __name__ == '__main__':
18     myserver = make_server('', 8011, mya)
19     print('监听8010')
20     myserver.serve_forever()

整个django框架就相当于def mya这个函数,只不过diango不是用函数,是用类包装起来。

对象加()调用是__call__的方法,__call__里面有这两个参数(environ, start_response),只要遵循这个http协议就会有这两个参数。wsgi就是将http请求拆开了,拆成python当中能够识别的变量,http直接来,能读出来就是字符串,但是还要做相应的处理,所以协议规定按照什么格式拆,拆到哪里,就是将数据当成字典拆到environ里面去,不管请求方式,请求头部等等然后再传到后面的可调用对象里面去,然后django就把这个东西包装成了对象request,所以request可以点http里的数据点出来。

开发模式

#  开发模式(前后端分离和前后端不分离)
# -前后端不分离项目(后端渲染页面)
# -前后端分离项目
# -前端和后端通过json格式数据交互(不需要写模板语言)请求页面用ajax发请求,前后端只做json数据的交互,json数据拿回来的时候就用dom来渲染我的页面,前端拿到数据,页面前端自己渲染
前端可以是前端,后台,移动端和微信小程序
https://www.cnblogs.com/liuqingzheng/p/10900502.html

cbv源码分析

-FBV和CBV
# -执行流程:
# -路由如果这么配置:url(r'^test/', views.Test.as_view()),
# 请求通过中间件后进入路由--->根据路由匹配,一旦成功,会执行后面函数(request)---》本质就是执行了as_view内部的view函数----》内部又调用了self.dispatch---->根据请求方式,执行不同的方法(必然get请求,就会执行咱么写的视图类的get方法)
# -尝试自己封装一个APIView,重写dispatch方法,在执行父类的dispatch之前,写一些逻辑,请求来了,就会执行这些逻辑
url()其实就是一个函数,views.Test.as_view()就是函数地址加括号,并且把request传进去,
#  python中一切皆对象
# def test():
# print('xxxx')
# test.name='lqz'
# print(test.name)

restful规范(importment,interview)

一 什么是RESTful

  • REST与技术无关,代表的是一种软件架构风格,REST是Representational State Transfer的简称,中文翻译为“表征状态转移”
  • REST从资源的角度类审视整个网络,它将分布在网络中某个节点的资源通过URL进行标识,客户端应用通过URL来获取资源的表征,获得这些表征致使这些应用转变状态
  • REST与技术无关,代表的是一种软件架构风格,REST是Representational State Transfer的简称,中文翻译为“表征状态转移”
  • 所有的数据,不过是通过网络获取的还是操作(增删改查)的数据,都是资源,将一切数据视为资源是REST区别与其他架构风格的最本质属性
  • 对于REST这种面向资源的架构风格,有人提出一种全新的结构理念,即:面向资源架构(ROA:Resource Oriented Architecture)
  • 资源就是实实存在的东西,如从动物园中新增一头动物,杀死一头动物    -10条
#     -1 API与用户的通信协议,总是使用HTTPs协议。(http不安全,数据被截断,数据就会全部展示出来)
# -2 域名有区分
      (dtl是模板语言,可以使用python等进行模板渲染再返回给前端)
      (后台管理并没有做前后端分离,用的就是dtl,而不是前端渲染)
# -https://api.example.com   尽量将API部署在专用域名(会存在跨域问题)
# -https://example.org/api/ 访问api代表就是访问路由接口
# -3 版本
      (就是如微博开一个接口,然后我写一个app去访问这个接口,需要传入两个参数,返回一个参数,然后后期微博数据需要改动,
       变成了一个接口需要传入三个参数,返回两个参数,不可能去改变我的app,只能再更新一个微博版本,开一个新的接口,
      然后app去连接一个新的接口,这期间就会有缓冲的过程)
# -可以放在路径中 URL 如:https://api.example.com/v1/
#        -可以放在请求头中  跨域时,引发发送多次请求
# -4 路径,视网络上任何东西都是资源,均使用名词表示(重点)
# -https://api.example.com/v1/zoos
# -5 通过method 区分是什么操作
# -get表示获取
# -post表示新增
# -delete表示删除
# -patch/put 表示修改
# -6 过滤,通过在url上传参的形式传递搜索条件
      
  • https://api.example.com/v1/zoos?limit=10:指定返回记录的数量
  • https://api.example.com/v1/zoos?offset=10:指定返回记录的开始位置
  • https://api.example.com/v1/zoos?page=2&per_page=100:指定第几页,以及每页的记录数
  • https://api.example.com/v1/zoos?sortby=name&order=asc:指定返回结果按照哪个属性排序,以及排序顺序
  • https://api.example.com/v1/zoos?animal_type_id=1:指定筛选条件

# -7 状态码
# {"status_code":100}
200 OK - [GET]:服务器成功返回用户请求的数据,该操作是幂等的(Idempotent)。
201 CREATED - [POST/PUT/PATCH]:用户新建或修改数据成功。
202 Accepted - [*]:表示一个请求已经进入后台排队(异步任务)
204 NO CONTENT - [DELETE]:用户删除数据成功。
400 INVALID REQUEST - [POST/PUT/PATCH]:用户发出的请求有错误,服务器没有进行新建或修改数据的操作,该操作是幂等的。
401 Unauthorized - [*]:表示用户没有权限(令牌、用户名、密码错误)。
403 Forbidden - [*] 表示用户得到授权(与401错误相对),但是访问是被禁止的。
404 NOT FOUND - [*]:用户发出的请求针对的是不存在的记录,服务器没有进行操作,该操作是幂等的。
406 Not Acceptable - [GET]:用户请求的格式不可得(比如用户请求JSON格式,但是只有XML格式)。
410 Gone -[GET]:用户请求的资源被永久删除,且不会再得到的。
422 Unprocesable entity - [POST/PUT/PATCH] 当创建一个对象时,发生一个验证错误。
500 INTERNAL SERVER ERROR - [*]:服务器发生错误,用户将无法判断发出的请求是否成功。

更多看这里:http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html

# -8 错误处理,应返回错误信息
# {"status_code":100,'msg':'登录成功'}
# {"status_code":101,'msg':'用户名错误'}
# -9 返回结果,针对不同操作,服务器向用户返回的结果
# -get获取所有资源/get获取一个资源
# -127.0.0.1/api/vi/books 获取所有图书
# {"status_code":100,'msg':'获取成功',data:[{},{}]}
# -127.0.0.1/api/vi/books/3 获取id为3的图书
# {"status_code":100,'msg':'获取成功',data:{name:xx,....}}
# -新增数据,把新增的数据再返回
# -修改了数据,返回完整的资源对象
# -删除数据,返回一个空文档
    • 错误处理,应返回错误信息,error当做key。
      1
      2
      3
      {
           error:  "Invalid API key"
      }
    • 返回结果,针对不同操作,服务器向用户返回的结果应该符合以下规范。
      1
      2
      3
      4
      5
      6
      GET  / collection:返回资源对象的列表(数组)
      GET  / collection / resource:返回单个资源对象
      POST  / collection:返回新生成的资源对象
      PUT  / collection / resource:返回完整的资源对象
      PATCH  / collection / resource:返回完整的资源对象
      DELETE  / collection / resource:返回一个空文档

#
# -10 返回结果中提供链接
Hypermedia API,RESTful API最好做到Hypermedia,即返回结果中提供链接,连向其他API方法,使得用户不查文档,也知道下一步应该做什么。
1
2
3
4
5
6
{ "link" : {
   "rel" :    "collection https://www.example.com/zoos" ,
   "href" :   "https://api.example.com/zoos" ,
   "title" "List of zoos" ,
   "type" :   "application/vnd.yourformat+json"
}}

django编写restful接口

#  DG软件
# -pycharm开发
# -idea
# -goland
# -AndroidStadio
不同程序可以用同一个数据库
views.py
from django.shortcuts import render
from django.http import JsonResponse
# Create your views here.
from app01 import models
def Book(request):
    #获取所有的图书
    if request.method == 'GET':
        books = models.Book.objects.all()
        #把queryset对象转成json格式的字符串
        # li = []
        # for book in books:
        #     bo = {'name':book.name,'publish':book.publish}
        #     li.append(bo)
        #列表推导式
        li=[{'name':book.name,'publish':book.publish} for book in books ]

        response = {'code':100,'msg':'查询成功','data':li}
        #safe=False 如果序列化的对象中有列表,需要设置
        return JsonResponse(response ,safe=False,json_dumps_params={'ensure_ascii':False})

models.py
from
django.db import models # Create your models here. class Book(models.Model): id = models.AutoField(primary_key=True) name = models.CharField(max_length=32) publish = models.CharField(max_length=32)

 1    def __init__(self, data, encoder=DjangoJSONEncoder, safe=True,
 2                  json_dumps_params=None, **kwargs):
 3         if safe and not isinstance(data, dict):
 4             raise TypeError(
 5                 'In order to allow non-dict objects to be serialized set the '
 6                 'safe parameter to False.'
 7             )
 8         if json_dumps_params is None:
 9             json_dumps_params = {}
10         kwargs.setdefault('content_type', 'application/json')
11         data = json.dumps(data, cls=encoder, **json_dumps_params)
12         super(JsonResponse, self).__init__(content=data, **kwargs)
源码

APIView源码简单分析

# 6 drf:APIView 的源码,Requset的源码
# -安装:
# -pip3 install djangorestframework
# -pycharm中安装
# -使用
# -第一步,再写视图,都写cbv
# from rest_framework.views import APIView
# class Books(APIView):
# pass
# -在setting中配置
# INSTALLED_APPS= [
# 。。。。。
# 'rest_framework'
# ]
#
# -源码分析:
# 继承了APIView 之后:
# -1 所有的请求都没有csrf的认证了
# -2 在APIView中as_view本质还是调用了父类的as_view(View的as_view)
# -3 as_view中调用dispatch -----》这个dispatch是APIView的dispatch
    @classmethod
    def as_view(cls, **initkwargs):
        """
        Store the original class on the view function.

        This allows us to discover information about the view when we do URL
        reverse lookups.  Used for breadcrumb generation.
        """
        if isinstance(getattr(cls, 'queryset', None), models.query.QuerySet):
            def force_evaluation():
                raise RuntimeError(
                    'Do not evaluate the `.queryset` attribute directly, '
                    'as the result will be cached and reused between requests. '
                    'Use `.all()` or call `.get_queryset()` instead.'
                )
            cls.queryset._fetch_all = force_evaluation

        view = super(APIView, cls).as_view(**initkwargs)
        view.cls = cls
        view.initkwargs = initkwargs

        # Note: session based authentication is explicitly CSRF validated,
        # all other authentication is CSRF exempt.
        return csrf_exempt(view)
源码
def csrf_exempt(view_func):
    """
    Marks a view function as being exempt from the CSRF view protection.
    """
    # We could just do view_func.csrf_exempt = True, but decorators
    # are nicer if they don't have side-effects, so we return a new
    # function.
    def wrapped_view(*args, **kwargs):
        return view_func(*args, **kwargs)
    wrapped_view.csrf_exempt = True
    return wraps(view_func, assigned=available_attrs(view_func))(wrapped_view)
源码
class View(object):
    """
    Intentionally simple parent class for all views. Only implements
    dispatch-by-method and simple sanity checking.
    """

    http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']

    def __init__(self, **kwargs):
        """
        Constructor. Called in the URLconf; can contain helpful extra
        keyword arguments, and other things.
        """
        # Go through keyword arguments, and either save their values to our
        # instance, or raise an error.
        for key, value in six.iteritems(kwargs):
            setattr(self, key, value)

    @classonlymethod
    def as_view(cls, **initkwargs):
        """
        Main entry point for a request-response process.
        """
        for key in initkwargs:
            if key in cls.http_method_names:
                raise TypeError("You tried to pass in the %s method name as a "
                                "keyword argument to %s(). Don't do that."
                                % (key, cls.__name__))
            if not hasattr(cls, key):
                raise TypeError("%s() received an invalid keyword %r. as_view "
                                "only accepts arguments that are already "
                                "attributes of the class." % (cls.__name__, key))

        def view(request, *args, **kwargs):
            self = cls(**initkwargs)
            if hasattr(self, 'get') and not hasattr(self, 'head'):
                self.head = self.get
            self.request = request
            self.args = args
            self.kwargs = kwargs
            return self.dispatch(request, *args, **kwargs)
        view.view_class = cls
        view.view_initkwargs = initkwargs

        # take name and docstring from class
        update_wrapper(view, cls, updated=())

        # and possible attributes set by decorators
        # like csrf_exempt from dispatch
        update_wrapper(view, cls.dispatch, assigned=())
        return view
源码

APIView的dispatch方法和request类分析

    -APIVIew的dispatch方法:
# -1 对原生request对象做了一层包装(面向对象的封装),以后再用的request对象都新的request对象
# -2 在APIView中self.initial(request, *args, **kwargs),里面有频率控制,权限控制和认证相关
# -3 根据请求方法执行咱们写的视图类中的相应方法
# --视图类中方法的request对象,已经变成了封装后的request
# -Request类:
# -1 原生的request是self._request
# -2 取以post形式提交的数据,从request.data中取(urlencoded,formdata,json格式)
# -3 query_params 就是原生request的GET的数据
# -4 上传的文件是从FILES中取
# -5 (重点)其他的属性,直接request.属性名(因为重写了__getattr__方法)

postman的安装和使用

美化jason的格式

猜你喜欢

转载自www.cnblogs.com/huangxuanya/p/11121222.html