zoukankan      html  css  js  c++  java
  • django框架之视图系统和路由系统

    内容回顾:

        1. tags
            1. for循环
                {% for name in name_list %}
                    {{ name }}
                {% endfor %}
                
                {% for name in name_list %}
                    {{ name }}
                {% empty %}
                    空空如也
                {% endfor %}
                
                forloop   {  }
                    forloop.counter      当前循环的索引值 从1开始
                    forloop.counter0     当前循环的索引值 从0开始
                    forloop.revcounter   当前循环的索引值(倒序) 到1结束
                    forloop.revcounter0  当前循环的索引值(倒序) 到0结束
                    forloop.first         单前循环是否是第一次循环  布尔值
                    forloop.last         单前循环是否是最后一次循环  布尔值
                    forloop.parentloop   当前循环的外层循环
                    
                上台阶,可以一次上1个台阶,可以上2个台阶,可以上3个台阶。问有n个台阶,有多少种走法?
            2. if判断
                {% if 条件 %}
                    操作
                {% endif %}
                
                {% if 条件 %}
                    操作
                {% else %}
                    其他操作
                {% endif %}
                
                {% if 条件 %}
                    操作
                {% elif 条件 %}
                    不同操作
                {% else %}
                    其他操作
                {% endif %}
                注意事项:
                    1. 不能连续判断 a > b > C   用and连接
                    2. 不支持算数运算  +-*/ 用filter
            3. csrf_tokrn
                使用:在form表单中使用
                效果:添加了一个隐藏的input标签,标签名叫csrfmiddlewaretoken 值:随机字符串
                作用:提交POST请求
            4. 注释  {# 注释部分 #}
            
        2. 母板和继承
            1.为什么要用母板和继承:
                很多页面有重复或相似的代码,减少代码的重复和修改方便才用母板和继承
            2.具体步骤:
                1. 创建一个母板,'base.html' 将多个页面的重复代码提取出来
                2. 在母板中定义多个block,来区分不同页面的不同内容
                3. 在子页面中继承母板  {% extends 'base.html' %}
                4. 在block中写自己页面独特的内容
                
            3. 注意事项
                1. {% extends 'base.html' %} 写在第一个行
                2. {% extends 'base.html' %}  base.html加上引号  不然当做是变量
                3. 通常定义多个block,还有一个page-css 和 page-js
        3. 组件
            将一小部分的HTML代码写在一个模板中。———》 组件
            在其他的页面中 {% include 'nav.html' %}
            
        4. 静态文件的内容
            {% load static %}
            "{% static 'css/mycss.css' %}"    ——》 /static/css/mycss.css
            
            {% get_static_prefix %}  —— 》  /static/
            
            "{% get_static_prefix %}css/mycss.css"
                
                
        5. 自定义simple_tag 和 inclusion_tag

    今日内容:

    视图系统

    视图:

    一个视图函数(类),简称视图,是一个简单的Python 函数(类),它接受Web请求并且返回Web响应。

    响应可以是一张网页的HTML内容,一个重定向,一个404错误,一个XML文档,或者一张图片。

    简单的说我们通常在views写的就是视图。只不过我们写的是基于函数的视图,即FBV。把视图写成基于类的,就是CBV啦。

    这是FBV

    def add_publisher(request):
        new_name = ''
        err_msg = ''
        if request.method == 'POST':
            new_name = request.POST.get('publisher_name')
            if new_name:
                publisher_obj_list = models.Publisher.objects.filter(name = new_name)
                if not publisher_obj_list:
                    models.Publisher.objects.create(name = new_name)
                    return redirect('/publisher/')
                else:
                    err_msg = '数据已存在'
            else:
                err_msg = '数据不能为空'
        return render(request, 'add_publisher.html', {'old_name': new_name, 'err_msg': err_msg})

    改成这样就是CBV啦:

    from django.views import View
    class Addpublisher(View):
        def get(self,request):
            return render(request, 'add_publisher.html')
        def post(self,request):
            new_name = request.POST.get('publisher_name')
            publisher_obj_list = models.Publisher.objects.filter(name=new_name)
            if not publisher_obj_list:
                models.Publisher.objects.create(name=new_name)
                return redirect('/publisher/')
            else:
                err_msg = '数据已存在'
                return render(request, 'add_publisher.html',{'err_msg':err_msg})

    往深入的讲,他其实是实现了View中的dispatch方法,所以这个dispatch我们可以自己定义:让他去执行父类的dispatch方法:

    from django.views import View
    class Addpublisher(View):
        def dispatch(self, request, *args, **kwargs):
          print('处理请求之前') ret =
    super().dispatch(self, request, *args, **kwargs)     print('处理请求之后')

    def get(self,request):
         print('这是get请求')
    return render(request, 'add_publisher.html') def post(self,request): new_name = request.POST.get('publisher_name') publisher_obj_list = models.Publisher.objects.filter(name=new_name) if not publisher_obj_list: models.Publisher.objects.create(name=new_name) return redirect('/publisher/') else: err_msg = '数据已存在' return render(request, 'add_publisher.html',{'err_msg':err_msg})

    其实这个dispatch相当于装饰器的作用。

    简版的流程:
                    AddPublisher.as_view()   ——》 view 函数
                    当请求来的时候才执行view
                    view中执行:
                        1. 先实例化AddPublisher,给self
                        2. 执行self.dispatch()  
                            self 有dispatch 就执行自己的
                                 没有就是执行 父类(View)的dispatch方法
                        3. dispatch中执行:
                            先通过反射获取到AddPublisher中定义get或者post方法。
                            执行get或者post方法 返回httpresponse对象
                        4. view接收到dispatch的返回值——httpresponse对象
                        5. view返回httpresponse对象

    接下来我们给视图加上装饰器:

      装饰器的作用是在函数之前或者之后做一些操作,并且不改变函数的调用方式。

      

    def wrapper(func):
        def inner(*args,**kwargs):
            now = time.time()
            ret = func(*args,**kwargs)
            print('函数执行的时间是{}'.format(time.time()-now))
            return ret
        return inner
    #增加出版社
    @wrapper
    def add_publisher(request):
        new_name = ''
        err_msg = ''
        if request.method == 'POST':
            new_name = request.POST.get('publisher_name')
            if new_name:
                publisher_obj_list = models.Publisher.objects.filter(name = new_name)
                if not publisher_obj_list:
                    models.Publisher.objects.create(name = new_name)
                    return redirect('/publisher/')
                else:
                    err_msg = '数据已存在'
            else:
                err_msg = '数据不能为空'
        return render(request, 'add_publisher.html', {'old_name': new_name, 'err_msg': err_msg})

    接下来我们给CBV加上装饰器:

    from django.views import View
    from django.utils.decorators import method_decorator
    class Addpublisher(View):
        # def dispatch(self, request, *args, **kwargs):
        #     return super().dispatch(self, request, *args, **kwargs)
    
        @method_decorator(wrapper)  #为get请求加上装饰器
        def get(self,request):
            return render(request, 'add_publisher.html')
    def post(self,request): new_name = request.POST.get('publisher_name') publisher_obj_list = models.Publisher.objects.filter(name=new_name) if not publisher_obj_list: models.Publisher.objects.create(name=new_name) return redirect('/publisher/') else: err_msg = '数据已存在' return render(request, 'add_publisher.html',{'err_msg':err_msg})

    给dispatch方法加上装饰器,get和post请求就都加上装饰器了。

    如果要在类上加装饰器,就要这样写@method_decorator(wrapper,name='get')

                    @method_decorator(wrapper,name='post')

     request对象:

        request属性:
                request.method  请求方式 GTE POST
                request.GET      ——》 字典  URL上传的参数
                request.POST     ——》 字典  form表单传的参数

        request.FILES    上传的文件

       request.path_info     返回用户访问url,不包括域名

        request.body            请求体,byte类型 request.POST的数据就是从body里面提取到的(gest请求没有请求体)

      我们来写一个上传的实例

    views中的代码:

    def upload(request):
        if request.method == 'POST':
            print(request.FILES)
            upload_obj = request.FILES['file_name']
            with open(upload_obj.name,'wb')as f:
                for chunk in upload_obj.chunks():
                    f.write(chunk)
        return render(request,'upload.html')

    html的代码:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <form action=""method="post" enctype="multipart/form-data">
        {% csrf_token %}
        <input type="file" name="file_name" >
        <button>提交</button>
    </form>
    </body>
    </html>

    request方法:

      request.path_info        url路径不包含url参数和域名

      request.get_full_path()  url路径包含url参数

      request.get_host()    获取ip和端口

     

    Response对象       

    response方法:

                1. HttpResponse 类  字符串
                2. render        返回一个HTML页面
                3. redirect     跳转  重定向  Location:/index/

    response属性:

      HttpResponse.content:响应内容

      HttpResponse.charset:响应内容的编码

      HttpResponse.status_code:响应的状态码

      

    JsonResponse对象:

    我们先写一个json数据:

    def json_data(request):
        import json
        data = {'name':'alex','age':73}
        return HttpResponse(json.dumps(data))

    然后我们在试一试django为我们提供的方法:

    from django.http import JsonResponse
    def json_data(request):
        # import json
        data = {'name':'alex','age':73}
        # return HttpResponse(json.dumps(data))
        return  JsonResponse(data)

    我们来说一说这两者的区别:

      如果浏览器拿到的是JsonResponse的格式会自动帮你解析。而且JsonResponse只会返回字典,如果要返回列表,JsonResponse(data,safe=False)

    路由系统:

    基本格式:

    urlpatterns = [
         url(正则表达式, views视图,参数,别名),]
    urlpatterns = [
        url(r'^articles/2003/$', views.special_case_2003),
        url(r'^articles/([0-9]{4})/$', views.book),
        url(r'^articles/([0-9]{4})/([0-9]{2})/$', views.book),
        url(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', views.book),
    
    
    
    
    ]
    我们匹配的时候加上小括号就是分组了,他就会将小括号里的内容以参数的形式传给views中的函数,而views中的
    函数就需要参数来接受。
    def book(request,*args):
        print(args)
        return HttpResponse('o98k')

    我们把这样的匹配叫做无名分组

    注意事项

    1. urlpatterns中的元素按照书写顺序从上往下逐一匹配正则表达式,一旦匹配成功则不再继续。
    2. 若要从URL中捕获一个值,只需要在它周围放置一对圆括号(分组匹配)。
    3. 不需要添加一个前导的反斜杠,因为每个URL 都有。例如,应该是^articles 而不是 ^/articles。
    4. 每个正则表达式前面的'r' 是可选的但是建议加上。
    分组命名匹配:
    在Python的正则表达式中,分组命名正则表达式组的语法是(?P<name>pattern),其中name是组的名称,pattern是要匹配的模式。

    我们也可以在分组的时候加上名字,比如:
    url(r'^book/(?P<year>[0-9]{4})/[0-9]{2}',views.book),

    这样views中的book函数在接受的时候就需要一个同名的参数来接受不然就会报错。
    def book(request,year):
        print(year)
        return HttpResponse('o98k')

    这就是命名分组!

    一个公司会有不同的业务,也会有不同的app,这样我们在写url的时候就可能会有重复。

    我们在项目名下的urls.py文件里可以这样写:

    from django.conf.urls import url,include
    from app01 import urls
    urlpatterns = [
        url(r'app01/',include(urls))
    ]
    

     剩下的就交给app01来做了。

    我们现在app01建一个urls.py文件,在文件中这样写:

    from django.conf.urls import url
    from app01 import views
    urlpatterns = [
        url(r'^book/(?P<year>[0-9]{4})/[0-9]{2}',views.book),
    ]

    然后再views的文件中写book函数:

    def book(request,year):
        print(year)
        return HttpResponse('o98k')

    同样我们也可以有多个app文件。

    项目名的urls.py文件下这样写:

    from django.conf.urls import url,include
    from app01 import urls as app01_urls
    from app02 import urls as app02_urls
    urlpatterns = [
        url(r'app01/',include(app01_urls)),
        url(r'app02/',include(app02_urls))
    ]

    在app01创建一个urls的py文件写:

    from django.conf.urls import url
    from app01 import views
    urlpatterns = [
        url(r'^book/(?P<year>[0-9]{4})/[0-9]{2}',views.book),
    ]

    在app02创建一个urls的py文件写:

    
    
    from django.conf.urls import url
    from app02 import views
    urlpatterns = [
        url(r'^book/(?P<year>[0-9]{4})/[0-9]{2}',views.book),
    ]
    
    

    然后分别写好app01和app02下的book函数。

    命名URL和URL反向解析:

    我们在 url后面加上一个名字,name属性,这样:

    url(r'^json_data/',views.json_data,name='data'),
    就可以在views的函数中进行向解析 print(reverse('data'))
    具体代码就是这样的:

    url(r'^json_data/',views.json_data,name='josn_data'),
    在views函数中:
    def json_data(request):
        print(reverse('ison_data'))
        data = {'name':'alex','age':73}
        return  JsonResponse(data)

    打印出来的结果就是:/json_data/。

    在模板里面可以这样引用:

    {% url 'jaon_data' %}


    说的简单点就是在url起一个名字,然后reverse通过这个名字反向解析拿到url地址。



    参数是这样传的:
    无名传参:
    url(r'^book/([0-9]{4})/[0-9]{2}',views.book,name='book')
      函数中的参数:
      reverse('book',args=('1995'))
      模板中的参数:
      {%url 'book' '1995'%}

     命名传参:

    url(r'^book/(?P<mouth>[0-9]{4})/[0-9]{2}',views.book,name='book')
      函数中的参数:
      reverse('book',kwargs={'mouth':'1995'})
      模板中的参数:
      {%url 'book' mouth='1995'%}
     namespace:
    如果说qpp01下和app02下有相同name的url,那么在视图中反向解析的时候找的会是谁的url呢?这就需要在项目名下的include里加一个参数
    namespace='app01',namespace='app02',然后再视图中reverse('app01:index')
                               reverse('app02:index')
                         在模板中也是一样{%url 'app01:index'%}

    举个例子:

    
    

    project中的urls.py

    
    
    复制代码
    from django.conf.urls import url, include
     
    urlpatterns = [
        url(r'^app01/', include('app01.urls', namespace='app01')),
        url(r'^app02/', include('app02.urls', namespace='app02')),
    ]
    复制代码
    
    

    app01中的urls.py

    
    
    复制代码
    from django.conf.urls import url
    from app01 import views
     
    app_name = 'app01'
    urlpatterns = [
        url(r'^(?P<pk>d+)/$', views.detail, name='detail')
    ]
    复制代码
    
    

    app02中的urls.py

    
    
    复制代码
    from django.conf.urls import url
    from app02 import views
     
    app_name = 'app02'
    urlpatterns = [
        url(r'^(?P<pk>d+)/$', views.detail, name='detail')
    ]
    复制代码
    
    

    现在,我的两个app中 url名称重复了,我反转URL的时候就可以通过命名空间的名称得到我当前的URL。

    
    

    语法:

    
    

    '命名空间名称:URL名称'

    
    

    模板中使用:

    
    
    {% url 'app01:detail' pk=12 %}
    
    

    views中的函数中使用

    
    
    v = reverse('app01:detail', kwargs={'pk':11})
     这样即使app中URL的命名相同,我也可以反转得到正确的URL了。
     
     
  • 相关阅读:
    NET Core中实现一个Token base的身份认证
    自定义一个服务器感受一下管道是如何监听、接收和响应请求的
    把商品卖给用户
    Mac版Visual Studio预览版
    Docker实战
    大数据的四大特点
    ElasticSearch Nosql
    Oracle和Elasticsearch数据同步
    关于MySql链接url参数的设置 专题
    linux date
  • 原文地址:https://www.cnblogs.com/yb635238477/p/9404179.html
Copyright © 2011-2022 走看看