django框架之视图系统和路由系统

Posted yb635238477

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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(rapp01/,include(app01_urls)),
    url(rapp02/,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/(?<Pmouth>[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了。
 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 




































































































































以上是关于django框架之视图系统和路由系统的主要内容,如果未能解决你的问题,请参考以下文章

Django 03. django框架之路由系统

人生苦短,我用python-- Day19 django框架之URL路由系统视图应用模板应用django之orm应用

Django视图层之路由配置系统(urls)

Django之路由系统

Django之 路由系统

Django之路由系统