django视图和模板(代码片段)

sanduzxcvbnm sanduzxcvbnm     2023-03-21     458

关键词:

一、概述

一个视图就是一个页面,通常提供特定的功能,使用特定的模板。例如:在一个博客应用中,你可能会看到下列视图:

  • 博客主页:显示最新发布的一些内容
  • 每篇博客的详细页面:博客的永久链接
  • 基于年的博客页面:显示指定年内的所有博客文章
  • 基于月的博客页面:显示指定月内的所有博客文章
  • 基于天的博客页面:显示指定日内的所有博客文章
  • 发布评论:处理针对某篇博客发布的评论

在我们的投票应用中,我们将建立下面的视图:

  • 问卷“index”页:显示最新的一些问卷
  • 问卷“detail”页面:显示一个问卷的详细文本内容,没有调查结果但是有一个投票或调查表单。
  • 问卷“results”页面:显示某个问卷的投票或调查结果。
  • 投票动作页面:处理针对某个问卷的某个选项的投票动作。

在Django中,网页和其它的一些内容都是通过视图来处理的。视图其实就是一个简单的Python函数(在基于类的视图中称为方法)。Django通过对比请求的URL地址来选择对应的视图。

在你上网的过程中,很可能看见过像这样的 URL: "ME2/Sites/dirmod.asp?sid=&type=gen&mod=Core+Pages&gid=A6CD4967199A42D9B65B1B" 。别担心,Django 里的 URL规则要比这优雅的多!

一个 URL 模式定义了一种 URL 的基本格式,比如:/newsarchive/<year>/<month>/

为了将 URL 和视图关联起来,Django 使用了 ‘URLconfs‘ 来配置。URLconf 将 URL 模式映射到视图。

二、编写视图

下面,打开polls/views.py文件,输入下列代码:

def detail(request, question_id):
    return HttpResponse("You‘re looking at question %s." % question_id)

def results(request, question_id):
    response = "You‘re looking at the results of question %s."
    return HttpResponse(response % question_id)

def vote(request, question_id):
    return HttpResponse("You‘re voting on question %s." % question_id)

然后,在polls/urls.py文件中加入下面的url模式,将其映射到我们上面新增的视图。

from django.urls import path

from . import views

urlpatterns = [
    # ex: /polls/
    path(‘‘, views.index, name=‘index‘),
    # ex: /polls/5/
    path(‘<int:question_id>/‘, views.detail, name=‘detail‘),
    # ex: /polls/5/results/
    path(‘<int:question_id>/results/‘, views.results, name=‘results‘),
    # ex: /polls/5/vote/
    path(‘<int:question_id>/vote/‘, views.vote, name=‘vote‘),
]

现在去浏览器中访问/polls/34/(注意:这里省略了域名。另外,使用了二级路由后,url中都要添加字符串polls前缀,参考前面的章节),它将调用detail()函数,然后在页面中显示你在url里提供的ID。访问/polls/34/results//polls/34/vote/,将分别显示预定义的伪结果和投票页面。(PS:这里就不贴图了,请大家务必自己动手测试,多实践。)

上面访问的路由过程如下:当有人访问/polls/34/地址时,Django将首先加载mysite.urls模块,因为它是settings文件里设置的根URL配置文件。在该文件里,Django发现了urlpatterns变量,于是在其内按顺序进行匹配。当它匹配上了polls/,就裁去url中匹配的文本polls/,然后将剩下的文本“34/”,传递给polls.urls进行下一步的处理。在polls.urls中,又匹配到了<int:question_id>/,最终结果就是调用该模式对应的detail()视图,也就是下面的函数:

detail(request=<HttpRequest object>, question_id=34)

函数中的question_id=’34’参数,是由<int:question_id>/而来。使用尖括号“捕获”这部分 URL,且以关键字参数的形式发送给视图函数。上述字符串的question_id部分定义了将被用于区分匹配模式的变量名,而int则是一个转换器决定了应该以什么变量类型匹配这部分的 URL 路径。

没必要书写一个如下的较为愚蠢的包含.html的模式,它显然是没必要,不够简练的:

path(‘polls/latest.html‘, views.index),

三、编写能实际干点活的视图

每个视图至少做两件事之一:返回一个包含请求页面的HttpResponse对象或者弹出一个类似Http404的异常。其它的则随你便,你爱干嘛干嘛。

下面是一个新的index()视图,用于替代先前无用的index,它会根据发布日期显示最近的5个投票问卷。

from django.http import HttpResponse

from .models import Question


def index(request):
    latest_question_list = Question.objects.order_by(‘-pub_date‘)[:5]
    output = ‘, ‘.join([q.question_text for q in latest_question_list])
    return HttpResponse(output)

# Leave the rest of the views (detail, results, vote) unchanged

# 省略了那些没改动过的视图(detail, results, vote)

这里有个非常重要的问题:在当前视图中的HTML页面是硬编码的。如果你想改变页面的显示内容,就必须修改这里的Python代码。为了解决这个问题,需要使用Django提供的模板系统,解耦视图和模板之间的硬连接。

首先,在polls目录下创建一个新的templates目录,Django会在它里面查找模板文件。

项目的 TEMPLATES配置项描述了 Django 如何载入和渲染模板。默认的设置文件设置了 DjangoTemplates 后端,并将 APP_DIRS设置成了 True。这一选项将会让 DjangoTemplates 在每个 INSTALLED_APPS 文件夹中寻找 "templates" 子目录。这就是为什么尽管我们没有像在第二部分中那样修改 DIRS 设置,Django 也能正确找到 polls 的模板位置的原因。

在templates目录中,再创建一个新的子目录名叫polls,进入该子目录,创建一个新的html文件index.html。换句话说,你的模板文件应该是polls/templates/polls/index.html。因为 Django 会寻找到对应的app_directories ,所以你只需要使用polls/index.html就可以引用到这一模板了。

模板命名空间:

你也许会想,为什么不把模板文件直接放在polls/templates目录下,而是费劲的再建个子目录polls呢?设想这么个情况,有另外一个app,它也有一个名叫index.html的文件,当Django在搜索模板时,有可能就找到它,然后退出搜索,这就命中了错误的目标,不是我们想要的结果。解决这个问题的最好办法就是在templates目录下再建立一个与app同名的子目录,将自己所属的模板都放到里面,从而达到独立命名空间的作用,不会再出现引用错误。

现在,将下列代码写入文件polls/templates/polls/index.html:

% if latest_question_list %
    <ul>
    % for question in latest_question_list %
        <li><a href="/polls/ question.id /"> question.question_text </a></li>
    % endfor %
    </ul>
% else %
    <p>No polls are available.</p>
% endif %

同时,修改视图文件polls/views.py,让新的index.html文件生效:

from django.http import HttpResponse
from django.template import loader

from .models import Question


def index(request):
    latest_question_list = Question.objects.order_by(‘-pub_date‘)[:5]
    template = loader.get_template(‘polls/index.html‘)
    context = 
        ‘latest_question_list‘: latest_question_list,
    
    return HttpResponse(template.render(context, request))

上面的代码会加载polls/index.html文件,并传递给它一个参数。这个参数是一个字典,包含了模板变量名和Python对象之间的映射关系。

在浏览器中通过访问/polls/,你可以看到一个列表,包含“What’s up”的问卷,以及连接到其对应详细内容页面的链接点。

注意:如果你显示的是No polls are available.说明你前面没有添加Questions对象。前面的大量手动API操作你没有做。没关系,我们在admin中追加对象就可以。

快捷方式:render()

在实际运用中,加载模板、传递参数,返回HttpResponse对象是一整套再常用不过的操作了,为了节省力气,Django提供了一个快捷方式:render函数,一步到位!

修改成下面的代码:

polls/views.py

from django.shortcuts import render

from .models import Question


def index(request):
    latest_question_list = Question.objects.order_by(‘-pub_date‘)[:5]
    context = ‘latest_question_list‘: latest_question_list
    return render(request, ‘polls/index.html‘, context)

注意,我们不再需要导入 loaderHttpResponse,而是从django.shortcuts导入了render。

render()函数的第一个位置参数是请求对象(就是view函数的第一个参数),第二个位置参数是模板。还可以有一个可选的第三参数,一个字典,包含需要传递给模板的数据。最后render函数返回一个经过字典数据渲染过的模板封装而成的HttpResponse对象。

四、返回404错误

现在让我们来编写返回具体问卷文本内容的视图:

# polls/views.py

from django.http import Http404
from django.shortcuts import render

from .models import Question
# ...
def detail(request, question_id):
    try:
        question = Question.objects.get(pk=question_id)
    except Question.DoesNotExist:
        raise Http404("Question does not exist")
    return render(request, ‘polls/detail.html‘, ‘question‘: question)

这里有个新知识点,如果请求的问卷ID不存在,那么会弹出一个Http404错误。

如果你想试试上面这段代码是否正常工作的话,你可以新建polls/detail.html文件,暂时写入下面的代码:

 question 

快捷方式:get_object_or_404()

就像render函数一样,Django同样为你提供了一个偷懒的方式,替代上面的多行代码,那就是get_object_or_404()方法,参考下面的代码:

polls/views.py

from django.shortcuts import get_object_or_404, render

from .models import Question
# ...
def detail(request, question_id):
    question = get_object_or_404(Question, pk=question_id)
    return render(request, ‘polls/detail.html‘, ‘question‘: question)

别说我没提醒你,和render一样,也需要从Django内置的快捷方式模块中导出get_object_or_404()

get_object_or_404()方法将一个Django模型作为第一个位置参数,后面可以跟上任意个数的关键字参数,如果对象不存在则弹出Http404错误。

同样,还有一个get_list_or_404()方法,和上面的get_object_or_404()类似,只不过是用来替代filter()函数,当查询列表为空时弹出404错误。(filter是模型API中用来过滤查询结果的函数,它的结果是一个列表集。而get则是查询一个结果的方法,和filter是一个和多个的区别!)

为什么我们使用辅助函数get_object_or_404()而不是自己捕获ObjectDoesNotExist异常呢?还有,为什么模型 API 不直接抛出ObjectDoesNotExist而是抛出 Http404呢?因为这样做会增加模型层和视图层的耦合性。指导 Django 设计的最重要的思想之一就是要保证松散耦合。一些受控的耦合将会被包含在 django.shortcuts 模块中。

五、 使用模板系统

回过头去看看我们的 detail() 视图。它向模板传递了上下文变量 question 。下面是 polls/detail.html 模板里正式的代码:

<h1> question.question_text </h1>
<ul>
% for choice in question.choice_set.all %
    <li> choice.choice_text </li>
% endfor %
</ul>

在模板系统中圆点.是万能的魔法师,你可以用它访问对象的属性。在例子 question.question_text 中,DJango首先会在question对象中尝试查找一个字典,如果失败,则尝试查找属性,如果再失败,则尝试作为列表的索引进行查询。

% for %循环中的方法调用——question.choice_set.all其实就是Python的代码question.choice_set.all(),它将返回一组可迭代的Choice对象,并用在% for %标签中。

这里我们对Django模板语言有个简单的印象就好,更深入的介绍放在后面。

六、删除模板中硬编码的URLs

polls/index.html文件中,还有一部分硬编码存在,也就是href里的“/polls/”部分:

<li><a href="/polls/ question.id /"> question.question_text </a></li>

它对于代码修改非常不利。设想如果你在urls.py文件里修改了路由表达式,那么你所有的模板中对这个url的引用都需要修改,这是无法接受的!

我们前面给urls定义了一个name别名,可以用它来解决这个问题。具体代码如下:

<li><a href="% url ‘detail‘ question.id %"> question.question_text </a></li>

Django会在polls.urls文件中查找name=‘detail‘的url,具体的就是下面这行:

path(‘<int:question_id>/‘, views.detail, name=‘detail‘),

举个栗子,如果你想将polls的detail视图的URL更换为polls/specifics/12/,那么你不需要在模板中重新修改url地址了,仅仅只需要在polls/urls.py文件中,将对应的正则表达式改成下面这样的就行了,所有模板中对它的引用都会自动修改成新的链接:

# 添加新的单词‘specifics‘
path(‘specifics/<int:question_id>/‘, views.detail, name=‘detail‘),

七、URL names的命名空间

本教程例子中,只有一个app也就是polls,但是在现实中很显然会有5个、10个、更多的app同时存在一个项目中。Django是如何区分这些app之间的URL name呢?

答案是使用URLconf的命名空间。在polls/urls.py文件的开头部分,添加一个app_name的变量来指定该应用的命名空间:

from django.urls import path

from . import views

app_name = ‘polls‘
urlpatterns = [
    path(‘‘, views.index, name=‘index‘),
    path(‘<int:question_id>/‘, views.detail, name=‘detail‘),
    path(‘<int:question_id>/results/‘, views.results, name=‘results‘),
    path(‘<int:question_id>/vote/‘, views.vote, name=‘vote‘),
]

现在,让我们将代码修改得更严谨一点,将polls/templates/polls/index.html中的

<li><a href="% url ‘detail‘ question.id %"> question.question_text </a></li>

修改为:

<li><a href="% url ‘polls:detail‘ question.id %"> question.question_text </a></li>

注意引用方法是冒号,不是圆点也不是斜杠!

django模板(代码片段)

...er),具有耦合性低、重用性高、生命周期成本低等优点。Django框架的设计模式借鉴了MVC框架的思想,也是分成三部分,来降低各个部分之间的耦合性。Django框架的不同之处在于它拆分的三部分为:Model(模型)、Template(模板)... 查看详情

django模板(代码片段)

在上一章节中我们使用django.http.HttpResponse()来输出"HelloWorld!"。该方式将数据与视图混合在一起,不符合Django的MVC思想。本章节我们将为大家详细介绍Django模板的应用,模板是一个文本,用于分离文档的表现形式和内容。模板应... 查看详情

django之模板层(代码片段)

目录Django之模板层一、模板简介二、模板语法之变量三、模板语法之标签四、自定义过滤器和标签五、模板的导入和继承六、静态文件配置Django之模板层一、模板简介在刚刚介绍完的视图层中我们提到,浏览器发送的请求信息会... 查看详情

django-模板(代码片段)

4.模板作为Web框架,Django提供了模板,可以很便利的动态生成HTML模版系统致力于表达外观,而不是程序逻辑模板的设计实现了业务逻辑(view)与显示内容(template)的分离,一个视图可以使用任意一个模板,一个模板可以供多个视... 查看详情

django框架+模板(代码片段)

...负责业务逻辑,并在适当的时候调用Model和Template此外,Django还有一个urls分发器,它的作用是将一个个URL的页面请求分发给不同的view处理,view再调用相应的Model和TemplateDjango之模板Django模板记两种特殊符号:  和 %% ... 查看详情

django-mtv(代码片段)

预览MTV模型Django基本命令视图层之路由配置系统视图层之视图函数模板层模型层基础模型层进阶MTV模型Django的MTV分别代表:Model(模型):负责业务对象与数据库的对象(ORM)Template(模板):负责如何把页面展示给用户View(视... 查看详情

django定义视图函数(代码片段)

Django定义视图函数视图函数主要在Django项目内app下的views.py文件内定义#调用模块方法fromdjango.shortcutsimportrender,HttpResponse,redirectdeffunc()#包含所有的请求数据....#返回字符串内容returnHttpRespon(‘字符串‘)#返回数据render(request,‘模板... 查看详情

django开发框架学习(代码片段)

Django开发框架学习Django流程重点Django介绍1.简介2.特点1)重量级框架2)MVT模式MVC模式说明Django的MVT3.Django学习资料为什么要搭建虚拟环境?如何搭建虚拟环境?如何使用虚拟环境?如何在虚拟环境中安装工具包?创建Django项目... 查看详情

django开发框架学习(代码片段)

Django开发框架学习Django流程重点Django介绍1.简介2.特点1)重量级框架2)MVT模式MVC模式说明Django的MVT3.Django学习资料为什么要搭建虚拟环境?如何搭建虚拟环境?如何使用虚拟环境?如何在虚拟环境中安装工具包?创建Django项目... 查看详情

07-django模板(代码片段)

模板介绍  作为web框架,Django提供了模板,用于编写html代码(嵌入模板代码,更快更方便的完成页面开发,在通过视图中渲染模板,将最终生成的页面返回给浏览器(客户端))。模板是关于外表的渲染的,程序逻辑反而不... 查看详情

django基础二(代码片段)

...关自定义过滤器和标签模板的继承视图层?三个工具:fromdjango.shortcutsimportrender,HttpResponse,redirect?视图函数必须有一个返回值并且返回值的数据类型必须是HttpResponse对象?render功能的实现,其原理是集合了Template,Context的功能后实现... 查看详情

django基础(代码片段)

python三大主流Web框架Django优点:大而全,自身携带的组件和功能特别特别多,类似于航空母舰缺点:过于笨重,所需功能不多时,Django依然提供这些功能,占据内存Flask优点:小而精自身携带的组件和功能特别特别少就类似于游... 查看详情

django的templates(模板)(代码片段)

目录Django的templates(模板)模板传值模板过滤器模板语法之标签常用标签之for标签常用标签之if标签常用标签之with标签自定义过滤器和标签模板的继承和导入模板的导入之include标签模板的继承/派生之extends标签,block标签Django的t... 查看详情

Django 教程:模板和视图

】Django教程:模板和视图【英文标题】:DjangoTutorial:TemplatesandViews【发布时间】:2012-11-1308:14:04【问题描述】:我正在完成官方的Django教程,我被困在第3部分。由于在第2部分的最后部分也使用了模板,我将描述我所做的:第2部... 查看详情

django——模板层:变量过滤器标签自定义标签和过滤器(代码片段)

...hon的代码分离开会更干净简洁更容易维护。我们可以使用Django的模板系统(TemplateSystem)来实现这种模式#django模板修改的视图函数defcurrent_time(req):fromdjango.templateimportTemplate,Contextnow=datetime.datetime.now()t 查看详情

django基础之视图(views)层模板层(代码片段)

目录Django基础之视图(views)层、模板层JsonResponse向前端返回一个json格式字符串的两种方式重写Django中的json的某个方法form表单上传文件FBV与CBVFBVCBV最精髓的部分Djangosettings源码分析及实际应用模板传值过滤器(|)标签前端if标签前端f... 查看详情

如何将模板视图和slug定义添加到一个视图中?(代码片段)

所以我正在研究一些Django但对它有点新意。我有这段代码:fromdjango.shortcutsimportrender,render_to_response,get_object_or_404from.modelsimportArticlefromdjango.views.genericimportTemplateViewdefview_post(request,slug):returnre 查看详情

django第三课模板(代码片段)

...多的模板系统。其中最知名最好用的就是DTL和Jinja2。DTL是DjangoTemlateLanguage三个单词的缩写。也就是Django自带的模板语言。当然也可以配置Django支持Jinja2等其他模板引擎,但是作为 查看详情