Django -- 视图层

三板斧

"""
HttpResponse
    返回字符串类型
render
    返回html页面 并且在返回给浏览器之前还可以给html文件传值
redirect
    重定向
"""
# 视图函数必须要返回一个HttpResponse对象  正确   研究三者的源码即可得处结论
# The view app01.views.index didn't return an HttpResponse object. It returned None instead.

# render简单内部原理
    from django.template import Template,Context
    res = Template('<h1>{{ user }}</h1>')
    con = Context({'user':{'username':'jason','password':123}})
    ret = res.render(con)
    print(ret)
    return HttpResponse(ret)

jsonResponse对象

"""
json格式的数据有什么用?
    前后端数据交互需要使用到json作为过渡 实现跨语言传输数据

前端序列化
    JSON.stringify()                    json.dumps()
    JSON.parse()                            json.loads()
"""
import json
from django.http import JsonResponse
def ab_json(request):
    user_dict = {'username':'jason好帅哦,我好喜欢!','password':'123','hobby':'girl'}

    l = [111,222,333,444,555]
    # 先转成json格式字符串
    # json_str = json.dumps(user_dict,ensure_ascii=False)
    # 将该字符串返回
    # return HttpResponse(json_str)
    # 读源码掌握用法
    return JsonResponse(user_dict,json_dumps_params={'ensure_ascii':False})
    # In order to allow non-dict objects to be serialized set the safe parameter to False.
    return JsonResponse(l,safe=False)  
    # 默认只能序列化字典 序列化其他需要加safe参数    

form表单上传文件

"""
form表单上传文件类型的数据
    1.method必须指定成post
    2.enctype必须换成formdata
"""
def ab_file(request):
    if request.method == 'POST':
        # print(request.POST)  # 只能获取普通的简直对数据 文件不行
        print(request.FILES)  # 获取文件数据
        # <MultiValueDict: {'file': [<InMemoryUploadedFile: u=1288812541,1979816195&fm=26&gp=0.jpg (image/jpeg)>]}>
        file_obj = request.FILES.get('file')  # 获取文件对象
        print(file_obj.name) # 获取文件名
        with open(file_obj.name,'wb') as f:
            for line in file_obj.chunks():  # 推荐加上chunks方法 加与不加效果一样
                f.write(line)

    return render(request,'form.html')

request对象方法

"""
request.method            获取标点提交的请求方式
    request.POST        获取POST请求数据
    request.GET            获取GET请求数据
request.FILES            获取文件
request.body            原生的浏览器发过来的二进制数据  后面详细的讲
request.path            只能拿到路由无法拿到路由后面的参数
request.path_info        只能拿到路由无法拿到路由后面的参数
request.get_full_path()  能过获取完整的url及问号后面的参数 
"""
    print(request.path)  # /app01/ab_file/
    print(request.path_info)  # /app01/ab_file/
    print(request.get_full_path())  # /app01/ab_file/?username=jason

FBV(function based view)与CBV(class based view)

  • 视图函数既可以是函数也可以是类
#CBV
    #CBV路由层:
    url(r'^login/',views.MyLogin.as_view())

    视图层:
    from django.views import View
    class MyLogin(View):
        def get(self,request):
            return render(request,'')

        def post(self,request):
            return HttpResponse('post方法')
  • CBV内部执行流程
# CBV本质上也是FBV,同样也是views.函数内存地址

#CBV
#路由
url(r'^login/', views.MyLogin.as_views())
'''
as_views()是类MyLogin所继承的父类View下的一个类方法
views.MyLogin.as_views()会优先执行as_views()方法并将MyLogin作为第一个参数传入
as_views()方法是一个闭包函数,内部嵌套了函数view,并将view的内存地址作为返回值返回
'''
# 路由层可变形为:url(r'^login/', views.view)
# 由此可以判断出CBV与FBV在路由匹配上本质是一样的,都是路由对应函数内存地址

# 后端
from django.views import View
class MyLogin(View):
    def get(self, request):
        return render(request, 'login.html')
    def post(self, request):
        return HttpResponse('post请求')
'''
view函数在当浏览器访问login时被触发,此时会先产生一个MyLogin的对象绑定给变量self

self.属性,依照面向对象的查找顺序先找自己再找对象所在的类,再找父类依次往上,直到找到为止。

view方法最终会返回一个self.dispatch方法的执行结果
很显然对象本身以及产生对象的MyLogin类中都没有dispatch方法,只有MyLogin继承的父类View中有

执行父类View下的dispatch方法,会先判断浏览器的请求是否合法。
如果合法,就会通过getattr反射到MyLogin中对应的方法,
handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
getattr(自定义类生成的对象self, 浏览器请求方式的小写, 如果请求不合法就执行第三个参数)
假设请求为get,handler = MyLogin下的get方法
假设请求为post,handler = MyLogin下的post方法
return handler(request, *args, **kwargs)
handler加括号,自动调用对应的方法执行,也就是实现了与FBV相同的展示效果
'''
# 结合源码,细品
class View(object):
    http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']
    
    @classonlymethod
    def as_view(cls, **initkwargs):
        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)
        return view
    
    def dispatch(self, request, *args, **kwargs):
        if request.method.lower() in self.http_method_names:
            handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
        else:
            handler = self.http_method_not_allowed
        return handler(request, *args, **kwargs)
    
    def http_method_not_allowed(self, request, *args, **kwargs):
        logger.warning(
            'Method Not Allowed (%s): %s', request.method, request.path,
            extra={'status_code': 405, 'request': request}
        )
        return http.HttpResponseNotAllowed(self._allowed_methods())

多对多三种创建方式

# 全自动:利用orm自动帮我们创建第三张关系表
    class Book(models.Model):
    name = models.CharField(max_length=32)
    authors = models.ManyToManyField(to='Author')
    class Author(models.Model):
    name = models.CharField(max_length=32)
    """
    优点:代码不需要你写 非常的方便 还支持orm提供操作第三张关系表的方法...
    不足之处:第三张关系表的扩展性极差
    """

# 纯手动
    class Book(models.Model):
    name = models.CharField(max_length=32)
    
    class Author(models.Model):
    name = models.CharField(max_length=32)
  
  class Book2Author(models.Model):
    book_id = models.ForeignKey(to='Book')
    author_id = models.ForeignKey(to='Author')
  '''
  优点:第三张表可以进行额外的扩展
  不足之处:需要写的代码较多,不能够再使用orm提供的简单的方法
  '''

# 半自动
class Book(models.Model):
    name = models.CharField(max_length=32)
    authors = models.ManyToManyField(to='Author',
                                     through='Book2Author',
                                     through_fields=('book','author')
                                     )
class Author(models.Model):
    name = models.CharField(max_length=32)
    # books = models.ManyToManyField(to='Book',
    #                                  through='Book2Author',
    #                                  through_fields=('author','book')
    #                                  )
class Book2Author(models.Model):
    book = models.ForeignKey(to='Book')
    author = models.ForeignKey(to='Author')

"""
through_fields字段先后顺序
    判断的本质: 通过第三张表查询对应的表 需要用到哪个字段就把哪个字段放前面
    
        
  半自动:可以使用orm的正反向查询 但是没法使用add,set,remove,clear这四个方法
"""

 

 
原文地址:https://www.cnblogs.com/zhenghuiwen/p/13027650.html