python -web-视图

一.视图定义

是一种字符串格式化的语法,基本用法是将值插入%s占位符的字符串中

  • Django的视图也可称为视图函数,即用Python函数来定义视图。视图函数接受Web请求,函数返回值就是响应内容。
  • 响应的内容可以是网页的HTML代码、XML文档、图像或者其他格式的内容。
  • 视图函数代码文件称为视图文件,文件名按惯例使用views.py,当然也可以使用其他的文件名。
  • 视图文件放在项目的同名子文件夹或项目的应用文件夹中。
  • 本节主要内容 定义和使用视图 返回错误 处理Http404异常
1.视图的基本结构

  • view_name:表示视图名称。
  • request :必选参数,接收请求对象(HttpRequest类的实例)。
  • args和kwargs:可选参数,用于接收URL中的额外参数。 
2.下面代码中的showData函数在Web页面中显示当前日期和从URL路径中获取的数据

第一步:新建 chapter05,创建项目mysite

django-admin startproject mysite

 

第二步:在同名项目下新建mysite/views.py

写入视图文件(views.py)

​​from django.http import HttpResponse
from datetime import date
from django.shortcuts import render

def showData(request,urlData):
    d=date.today()
    s='URL路径中的数据:%s<br>当前日期:%s'% (urlData,d)
    return HttpResponse(s)

配置根路由(urls.py)

from django.contrib import admin
from django.urls import path
from . import views
from mysite.views import showGetData

urlpatterns = [
    path('admin/', admin.site.urls),
    path('test<urlData>',views.showData),
]

 第三步:测试

http://127.0.0.1:8000/test1234

 二.处理请求和响应

  •  Django使用HttpRequest对象处理HTTP请求,使用HttpResponse对象处理HTTP响应。HttpRequest和HttpResponse类在django.http模块中定义。
  • 接收到客户端响应时,Django首先创建一个HttpRequest对象,该对象封装了请求相关的数据。然后Django调用匹配的视图函数,将HttpRequest对象传递给视图函数的第一个参数。视图函数负责返回一个HttpResponse对象,该对象封装了响应相关的数据。
  • 获取请求数据, 处理响应内容, 文件附件 ,生成CSV文件, 生成PDF文件 ,返回JSON字符串 ,使用响应模板, 重定向
1.GET 请求

视图文件(views.py)

扫描二维码关注公众号,回复: 17327622 查看本文章
def showGetData(request):
    s='请求上传数据:姓名=%s,年龄=%s'%(request.GET['name'],request.GET['age'])
    return HttpResponse(s)

配置根路由:

path('get/',views.showGetData),

测试:http://127.0.01:8000/get?name=abc&age=40 

2.HTML/文本

定义视图(views.py)

def showSomething(request):
    r=HttpResponse('<h1>一级标题<h1>',content_type="text/plain;charset=utf-8")
    r.write('<p>第二段<p>')
    r.write('three')
    return r

 配置根路由:

path('str',views.showSomething),

测试:127.0.0.1:8000/str 

3.文件附件

Django允许将响应内容以文件附件的形式返回。要返回文件附件,需要设置content_type参数和Content-Disposition标头.

定义视图(views.py)

def downloadFile(request):
    r = HttpResponse('文件内容',content_type="text/text;charset=utf-8")
    r ['Content-Disposition'] = 'attachment; filename="test.txt"'
    r.write('\n<h1>test<h1>')
    return r

 配置根路由(urls.py)

path('down/',views.downloadFile),

测试:127.0.0.1:8000/down

4.csv文件

使用Python的csv库,可以生成CSV格式的文件。

生成CSV文件的基本步骤如下。

  • (1)创建HttpResponse对象,并设置content_type和Content- Disposition。
  • (2)将HttpResponse对象作为csv.writer()的参数,创建CSV生成器。
  • (3)调用CSV生成器的writerow()、writerows()等方法向HttpResponse对象写入数据。
  • (4)返回HttpResponse对象。

定义视图(views.py)

import csv
def writecsv(request):
    r = HttpResponse(content_type="text/text")
    r ['Content-Disposition'] = 'attachment;filename="data.csv"'
    w= csv.writer(r)
    w.writerow(['one',1,3,5])
    w.writerow(['two','a','b','5',123])
    return r

配置根路由(urls.py)

path('csv/',views.writecsv),

测试:127.0.0.1:8000/csv

5.pdf文件

使用第三方的开源Python库ReportLab,可以在Django视图中动态生成PDF文件。

在Windows命令窗口中执行下面的命令安装ReportLab库。

定义视图(vies.py)

def writepdf(request):
    from reportlab.lib.units import cm
    from reportlab.pdfbase.ttfonts import TTFont
    from reportlab.pdfbase import pdfmetrics
    from reportlab.pdfgen import canvas
    from reportlab.lib.colors import ReportLabBlueOLD
    response = HttpResponse(content_type='application/pdf')
    response['Content-Disposition'] = 'attachment; filename="data.pdf"'
    pdfmetrics.registerFont(TTFont('songti','simsun.ttc'))
    c = canvas.Canvas(response,pagesize=(10*cm,5*cm))
    c.setFont('songti', 18)
    c.setFillColor('red')
    c.drawString(0.5*cm,4*cm,"python Django Web简明教程")
    c.showPage()
    c.save()
    return response

 配置根路由

path('pdf/',views.writepdf),

 测试:127.0.0.1:8000/pdf

 

 三.HttpResponse的子类 

HttpResponse类的两个重要子类。

1.json字符串

JsonResponse是HttpResponse的子类,用于封装JSON字符串响应,它将Content-Type的标头设置为application/json。

 定义视图(views.py)

def writejson(request):
    r=HttpResponse(content_type="application/json;charset=utf-8")
    r.write({'name':'zhangsan','data':[123,'abc']})

 配置根路由(urls.py)

path('json/',views.writejson),

测试: 127.0.0.1:8000/json

2.返回错误:

Django可以返回HTTP状态码和状态描述信息。 正常情况下,视图函数返回的HttpResponse对象的状态代码为200,表示服务器正确处理了响应。 Django还提供了一系列HttpResponse子类来返回各种HTTP响应

创建一个app

python manage.py startapp app

定义视图(views.py)

from django.shortcuts import render

# Create your views here.

from django.http import Http404,FileResponse
from django.http import HttpResponse
from django.http import HttpResponseRedirect
from django.http import HttpResponsePermanentRedirect
from django.http import HttpResponseNotModified
from django.http import HttpResponseBadRequest
from django.http import HttpResponseNotFound
from django.http import HttpResponseForbidden
from django.http import HttpResponseNotAllowed
from django.http import HttpResponseGone
from django.http import HttpResponseServerError

def testHttpResponseRedirect(request):
    return HttpResponseRedirect("/admin")

def testHttpResponsePermanentRedirect(request):
    return HttpResponsePermanentRedirect("/admin")

def testHttpResponseNotModified(request):
    return HttpResponseNotModified()

def testHttpResponseBadRequest(request):
    return HttpResponseBadRequest("参数类型错误")

def testHttpResponseNotFound(request):
    return HttpResponseNotFound("未找到请求")

def testHttpResponseForbidden(request):
    return HttpResponseForbidden('禁止访问请求的内容')

def testHttpResponseNotAllowed(request):
    return HttpResponseNotAllowed(['GET',],'不允许使用该方法')

def testHttpResponseGone(request):
    return HttpResponseGone("请求内容已不存在")

def testHttpResponseServerError(request):
    return HttpResponseServerError("服务器处理出错了")

def testStatusCode(request):
    return HttpResponse(status=401)

定义根路由(urls.py)

path('app/', include('app.urls')),

 定义子路由

from django.urls import path
from . import views

urlpatterns = [
    path('testHttpResponseRedirect/', views.testHttpResponseRedirect),
    path('testHttpResponsePermanentRedirect', views.testHttpResponsePermanentRedirect),
    path('testHttpResponseNotModified', views.testHttpResponseNotModified),
    path('testHttpResponseBadRequest', views.testHttpResponseBadRequest),
    path('testHttpResponseNotFound', views.testHttpResponseNotFound),
    path('testHttpResponseForbidden', views.testHttpResponseForbidden),
    path('testHttpResponseNotAllowed', views.testHttpResponseNotAllowed),
    path('testHttpResponseGone', views.testHttpResponseGone),
    path('testHttpResponseServerError', views.testHttpResponseServerError),
    path('testStatusCode', views.testStatusCode),
    
]

 

 

3.处理Http404异常 

HTTP 404错误表示服务器未找到客户请求的内容,这是最常见的HTTP错误

定义视图(views.py)

def testHttp404(reqyest):
    raise Http404('亲:没有找到你需要的内容!')
    return HttpResponse("ok")

配置子路由:

path('404/',views.testHttp404)

测试:

 4.重定向

django.shortcuts模块中的redirect()方法用于快速创建重定向

参数to可以是模型中返回URL的方法、视图名称或URL。

第一步:编写info.html文件(在TEMPLATES 设置中的 DIRS 列表配置该路径以及在 与app同一目录下的 templates 文件夹下创建)

配置setting文件

'DIRS': [os.path.join(BASE_DIR, 'templates')],

info.html文件: 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>使用响应的模板</title>
</head>
<body>
    <b>姓名:</b>{
   
   {name}} <br>
    <b>年龄:</b>{
   
   {age}}
</body>
</html>

第二步:定义视图(views.py)

from django.shortcuts import redirect
def useRedirect(request):    
    return redirect(showData,urlData='123')#重定向到5.1.1中定义的视图函数showData

from django.template.response import TemplateResponse
def useTemplateResponse(request):
    return TemplateResponse(request,'info.html',{'name':'张三','age':25})

 第三步:配置根路由:

path('redirect',views.useRedirect),
path('uset',views.useTemplateResponse),

第四步:测试网址:127.0.0.1:8000/redirect                                    127.0.0.1:8000/uset        

四.在视图中使用模型

1.在视图中输出模型数据

第一步:创建一个新的项目,创建一个新的应用app

django-admin startproject demo
python manage.py startapp app

第二步: 在应用app下配置models.py文件

from django.db import models
# Create your models here.
class user(models.Model):
    name = models.CharField(max_length=20)
    age = models.IntegerField()

第三步:配置setting.py文件注册数据库。把应用注册到INSTALLED_APPS里面

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'demo',
        'HOST':'localhost',
        'PORT': 3306,
        'USER':'root',
        'PASSWORD':'myy040715'
        }
}

 第四步:生成迁移文件,执行迁移文件

python manage.py makemigrations
python manage.py migrate

第五步:配置视图文件(views.py)

from django.shortcuts import render
from django.shortcuts import HttpResponse
# Create your views here.
from .import models
def useModels(request):
    usename = request.GET['name'] #获取客户端上传的name
    uage = request.GET['age'] #获取客户端上传的age
    models.user.objects.create(name=usename, age=uage)
    s="默认数据库中的user表数据:<br><table><tr><td>id</td><td>name</td><td>age</td></tr>"
    for u in models.user.objects.all():
        s+= "<tr><td>%s</td><td>%s</td><td>%s</td></tr>" % (u.id,u.name,u.age)
    return HttpResponse(s+ '</table>')

第六步:配置根路由:

from django.contrib import admin
from django.urls import path,include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('',include('app.urls'))
]

配置子路由:

path('model/',views.useModels),

第七步:运行manage.py

python manage.py runserver

第八步:测试网址:127.0.0.1:8000/model?name=zhangsan&age=20

2.数据分页 

django.core.paginator模块中的Paginator类用于实现数据分页。

2.1Paginator对象 

Paginator()构造函数用于创建Paginator对象(称为分页器)

  • object_list:用于分页的对象集合,可以是查询集、元组、列表或者其他可分片对象(带有count()或__len__()方法的对象)。必选参数。
  • per_page:每页中允许的最大对象数。必选参数。
  • orphans:用于控制最后一页的对象数。如果剩余的对象数小于或等于orphans值,则这些对象将被添加到上一页面,并使其成为最后一页。可选参数,默认值为0。
  • allow_empty_first_page:是否允许第一页为空。可选参数,默认值为True,即允许第一页为空。
  • count:返回所有页面中的对象总数。
  • num_pages:返回总页数。
  • page_range:返回页码迭代器,页码从1开始。
  • get_page(页码):返回指定页的Page对象,页码从1开始。该方法可处理超出范围或无效的页码。如果给定页码不是数字,则返回第一页。如果给定页码小于1或大于总页数,则返回最后一页。
  • page(页码):返回指定页的Page对象,它不处理超出范围或无效页码。指定的页码无效时会触发InvalidPage异常。
python manage.py shell
>>> from django.core.paginator import Paginator
>>> objects = ['john','paul','george','ringo']
>>> p = Paginator(objects,2)
#对objects进行分页,虽然objects只是个字符串列表,但是没关系,一样用。每页显示2条。
>>> p.count              #对象个数
4
>>> p.num_pages          #总共几页
2
>>> p.page_range         #分页范围
range(1, 3)
>>> p.per_page           #每页数据个数
2
2.2pages对象

第一步:定义视图(views.py)

def useModelsPaginator(request):
    objects = models.user.objects.all()
    pages = Paginator(objects, 2)
    page_number = request.GET['page']
    page = pages.get_page(page_number)
    data_list = page.object_list
    s = "数据分页显示<hr><table><tr><td>id</td><td>name</td><td>age</td></tr>"
    for u in data_list:
        s += "<tr><td>%s</td><td>%s</td><td>%s</td></tr>" % (u.id, u.name, u.age)
    s+= "</table><hr>"
    if (page.has_previous()):
        s += '<a href="/pages?page=%s">上一页<a/> <' % page.previous_page_number()
    s += '当前页: %s/%s' % (page.number, pages.num_pages)
    if page.has_next():
        s += '> <a href="/pages?page=%s">下一页<a/>' % page.next_page_number()
    return HttpResponse(s)

第二步:配置子路由:

path('pages/',views.useModelsPaginator)

第三步:测试127.0.0.1:8000/pages?page=2

  • Page对象用于处理指定页。通常调用分页器的page()或get_page()方法获得Page对象。
  • object_list:返回当前页的对象列表。
  • number:返回当前页的页码。
  • paginator:返回关联的Paginator对象。
  • has_next():有下一页时返回True,否则返回False。
  • has_previous():有上一页时返回True,否则返回False。
  • has_other_pages():有上一页或下一页时返回True,否则返回False。
  • next_page_number():返回下一页的页码。
  • previous_page_number():返回上一页的页码。
  • start_index():返回当前页中第一个对象在所有对象中的索引,索引从1开始。例如,总对象数为6,每页包含2个对象,则第二页的start_index()返回3。
  • end_index():返回当前页中最后一个对象在所有对象中的索引。例如,总对象数为6,每页包含2个对象,则第二页的end_index()返回4。

五.基于类的视图 

 基于类的视图指用类实现的视图,可通过定义其子类进行扩展。

1. 定义类视图

类视图允许在views.py的一个类中定义不同的方法,以处理同一功能以不同请求方式发送的请求。

有一个同一URL的GET请求和POST请求,以往函数的形式定义视图。需要使用if语句对两种请求方式分别进行处理并返回响应。

使用视图函数的形式定义视图
from django.shortcuts import render

# Create your views here.
from django.http import HttpResponse
from django.views import View
def my_view(request):
    if request.method == 'GET':
        return HttpResponse('GET result')
    elif request.method == 'POST':
        return HttpResponse('POST result')
使用基于类的视图
from django.shortcuts import render

# Create your views here.
from django.http import HttpResponse
from django.views import View
class Myview(View):
    def get(self,request):
        return HttpResponse('GET result')
    def post(self,request):
        return HttpResponse('POST result')

根路由:

from django.contrib import admin
from django.urls import path,include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('app/',include('app.urls'))
]

 子路由:

from django.contrib import admin
from django.urls import path
from .import views
from .views import Myview

urlpatterns = [
    path('myview/',views.Myview.as_view())
]

2.基于类的视图

Django处理视图类的基本步骤如下。

  • 第一步:执行as_view()方法,创建一个类的实例。
  • 第二步:调用setup()方法初始化实例的属性。
  • 第三步:调用dispatch()方法,根据HTTP请求方式(GET或POST等)调用匹配的实例方法。如果没有匹配的实例方法,则返回HttpResponseNotAllowed响应。
例一:html与视图放在一起

定义视图(views.py)

from django.shortcuts import render
from django.shortcuts import HttpResponse
# Create your views here.
from .import models
from django.views import View
class useClassview(View):
    news="使用基于类的视图useClassView"
    form='<form name = "input" action="" method="post">'\
                    +'请输入数据:<input type="text" name="data">'\
                    +'<input type="submit" value="提交"></form>'
    def get(self,request):
        out = self.news+'<br/>请求方法:GET<br/>'+self.form
        return HttpResponse(out)
    def post(self,request):
        out=self.news+'<br/>请求方法:POST<br/>'\
            +'上传数据为:'+request.POST['data'] + self.form
        return HttpResponse(out)

定义子路由(urls.py)

#path('useview/',views.useClassview.as_view()),
path('useview/',csrf_exempt(views.useClassview.as_view())),

  

例二:html和视图分开 

在app应用文件夹下创建templates下创建文件classview.html

先在settings.py里面配置templates文件路径

'DIRS': [os.path.join(BASE_DIR, 'templates')],

classview.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>使用基于类的视图</title>
</head>
<body>
    <h1>使用基于类的视图</h1>
    <hr>
    <form action="" name="input" method="post">
        {% csrf_token%}
        请求方法:{
   
   {method}}<br/>
        请输入数据: <input type="text"name="data"> <br>
        <input type="submit" value="提交">
    </form>
    上传的数据为{
   
   {out}}
</body>
</html>

定义视图(views.py)

class testclassView(View):
    def get(self,request):
        return render(request,'classview.html',{'method':'GET'})
    def post(self,request):
        out= request.POST['data']
        return render(request,'classview.html',{'out':out,'method':'POST'})

定义子路由:

path('testview/',views.testclassView.as_view()),

定义根路由:

path('',include('app.urls'))

 

3.扩展视图类

定义视图(views.py)

class subClassView(useClassview):
    news = '这是视图类useClassview的扩展类!'
    def get(self,request):
        out =self.news+'<br/>重载get()方法输出:请输入数据后提交!<br/>' + self.form
        return HttpResponse(out)

定义子路由:

from django.views.decorators.csrf import csrf_exempt
path('subview',csrf_exempt(views.subClassView.as_view())),

定义根路由:

path('',include('app.urls'))

 测试:

 4.设置视图类属性

两种配置类属性:一种是python类中定义属性的标准方法----直接重写父类的属性;

另一种是:在URL中将类属性配置为as_view()方法的关键字参数。

  1. Python类定义属性的标准方法

修改classview.html文件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{
   
   {title}}</title>
</head>
<body>
    
    <h1>使用基于类的视图</h1>
    <hr>
    <form action="" name="input" method="post">
        {% csrf_token%}
        请求方法:{
   
   {method}}<br/>
        请输入数据: <input type="text"name="data"> <br>
        <input type="submit" value="提交">
    </form>
    上传的数据为{
   
   {out}}
</body>
</html>

 修改testclassView类视图函数

class testclassView(View):
    timu = "基于类的视图"
    def get(self,request):
        return render(request,'classview.html',{'method':'GET','title':self.timu})
  1. 将类属性配置为as_view()方法的关键字参数

在配置URL时通过关键字参数为as_view()方法传参。

path('testview',views.testclassView.as_view(timu='将类属性配置为as_view()方法的关键字参数')),

 六.内置通用视图

1.通用试图

通用视图是视图开发中常见任务的抽象,使用通用视图,只需编写少量代码,便可快速开发数据的公共视图。

2.通用视图DetailView
  •  DetailView用于显示单个模型对象的数据。
  • 通常情况下,在URL中向视图提交对象的id,视图使用id获得模型对象,并将模型对象传递给模板。

使用DetailView显示user表特定用户的数据,并且在每个详情页面显示当前时间。

先定义模型(models.py)

from django.db import models

# Create your models here.
class user(models.Model):
    name = models.CharField(max_length=20)
    age = models.IntegerField()

 在setting.py配置数据库,应用hello,和DIRS

#第一处
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'demo',
        'HOST':'localhost',
        'PORT': 3306,
        'USER':'root',
        'PASSWORD':'myy040715'
    }
}

#第二处
'DIRS': [os.path.join(BASE_DIR, 'templates')],

生成迁移文件,执行迁移文件

python manage.py makemigrations
python manage.py migrate

 定义视图(views.py)

from typing import Any, Dict
from django.shortcuts import render
from app.models import user
# Create your views here.
from django.views.generic.detail import DetailView
from datetime import datetime
class userDatailView(DetailView):
    model = user
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['now'] = datetime.now()
        return context

定义根路由(urls.py)

from django.urls import path
# from django.views.decorators.csrf import csrf_exempt
from app import views
 
urlpatterns = [
    path('detail/<int:pk>',views.userDatailView.as_view()),

]

 静态文件(user_detail.html),位于应用app下文件夹templates下的app文件夹下的user_detail.html

 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    当前日期:{
   
   {now}}  <br>
    <b>id:</b>{
   
   {object.id}}

    <b>姓名:</b>{
   
   {object.name}}

    <b>年龄:</b>{
   
   {object.age}}
</body>
</html>

测试:127.0.0.1:8000/app/detail/1

3.通用视图ListView 

ListView用于显示多个模型对象的数据,数据显示格式由模板定义。

定义视图(views.py)

from django.views.generic import ListView
class userListView(ListView):
    model = user

定义路由(urls.py)

path('list/',views.userListView.as_view()),

 静态文件(list.html),位于应用app下文件夹templates下的app文件夹下的user_detail.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>使用内置List视图</title>
</head>
<body>
    默认数据库user表数据
    <table>
        <tr>
            <td>id</td>
            <td>name</td>
            <td>age</td>
        </tr>
        {% for user in object_list %}
        <tr>
            <td>{
   
   { user.id }}</td>
            <td>{
   
   { user.name }}</td>
            <td>{
   
   { user.age }}</td>
        </tr>
        {% endfor %}
    </table>
</body>
</html>

测试:127.0.0.1:8000/app/list/ 

猜你喜欢

转载自blog.csdn.net/2201_76041915/article/details/134936610