Django文档简化版——Django快速入门——创建一个基本的投票应用程序(3)

续上一篇,这一篇 着重于创建公共接口------"视图"

第三部分------3、视图和模板

1、概述

  • Django中视图------一类具有相同功能和模板网页的集合
  • 网页和其他内容由视图派生而来。
  • 视图是一个python函数or方法
  • 根据用户请求的URL(域名之后的部分)来选择使用哪个视图
  • 将URL与视图关联起来------URLconfs(将URL映射到视图)来配置

2、编写更多视图

在 polls/views 增加

python 复制代码
def detail(request,question_id):
    return HttpResponse("You're loooking 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 模块中

python 复制代码
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/34/"它将运行detail()函数,显示为:

同理访问"/polls/2/results/",或者访问"/polls/2/vote/":将看到:

原理------django依次访问了什么文件

  1. 访问根urls.py文件,即ROOT_URLCONF,按顺序遍历这些模式,匹配path("polls/",include("polls.urls")),并将剩余的文本发送给polls.urls
  2. Django 会匹配 path('int:question_id/', views.detail, name='detail'),其中 'int:question_id/' 表示将URL路径的这一部分解析为整数,并作为 question_id 参数传递给 detail 视图函数。
  3. 在polls/views,detail 函数接收两个参数:request 和 question_id。当你访问 /polls/34/ 时,question_id 的值为 34,因此视图函数会返回包含 "You're looking at question 34." 的响应。

总结:

1、Django加载项目的URL配置:mysite/urls.py。

2、匹配到包含的应用URL配置:polls/urls.py。

3、解析URL路径参数并调用相应视图函数:将 question_id 解析为 34,并调用 detail 视图函数。

4、视图函数处理请求并返回响应:detail 函数生成并返回响应。

3、写一个真正有用的视图

视图必须做的只有两件事:返回一个包含被请求页面的HttpResponse对象。或者抛出一个异常。

视图还可以做什么?视图可以从数据库读记录,可以使用一个模板引擎,,可以生成一个pdf文件,可以输出一个xml,可以创建一个zip文件,可以做任何你想做的事情。

接下来修改polls/views/index()函数,显示最近的五个问题

python 复制代码
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)
  • 这里有一个问题,页面的代码写死在了视图函数里,这里解释一下什么叫"写死",以及它的弊端

当我们说页面的设计"写死"在视图函数里时,意思是视图函数中包含了生成页面内容的具体代码 。如果你想修改页面的外观或布局,就必须直接编辑这些视图函数。这种做法的问题在于:

1、难以维护和更新:每次需要修改页面的外观或布局时,都必须直接更改视图函数中的代码,可能导致代码变得复杂和难以维护。

2、代码与内容耦合:视图函数不仅负责处理请求逻辑,还负责生成HTML内容,使得业务逻辑和页面设计耦合在一起

3、复用性差:如果不同的视图函数需要共享相同的HTML结构或样式,每个视图函数都必须重复相同的HTML代码,导致代码重复和不易复用。

所以要使用Django的模板系统,只需要创建一个视图,就可以将页面的设计从代码里分离出来

首先,创建polls/templates目录。Django会在这个目录里查找模板文件

接着创建templates/polls/index.html

  • 避免模板文件名称冲突,我们应该将模板文件放在与应用同名的子文件夹中。这样做的好处是,如果你有多个应用程序,它们可以使用相同名称的模板文件而不会互相冲突
  • 命名空间:为了帮助Django区分不同应用的模板,我们将模板文件放在与应用同名的子文件夹中。这就是所谓的命名空间。例如,对于 polls 应用,我们应该在 polls/templates 目录下再创建一个 polls 子目录。

在index.html文件中:

python 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Polls Index</title>
</head>
<body>
    {% 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 %}
</body>
</html>
python 复制代码
<ul>:表示无序列表(unordered list)。通常用于列出项目,每个项目由 <li>(列表项)标签表示。

<li>:表示列表中的项目(list item)。在无序列表 <ul> 或有序列表 <ol> 中使用。

<a>:表示超链接(anchor)。用于创建链接,可以导航到其他页面或资源。href 属性指定链接目标。

<p>:表示段落(paragraph)。用于定义文档中的段落,浏览器会自动在段落前后添加一些空白,以便段落与其他内容分开。

{{ }}:Django模板语法,用于输出变量的值。例如,{{ question.id }} 输出问题的ID,{{ question.question_text }} 输出问题的文本。

{% %}:Django模板标签,用于执行逻辑语句或控制流。例如,{% if latest_question_list %} 检查 latest_question_list 是否有数据,{% for question in latest_question_list %} 循环遍历 latest_question_list 中的每个问题,{% endif %} 结束 if 语句,{% endfor %} 结束 for 循环。

接下来更新polls/views.py中的Index视图

python 复制代码
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))#模板渲染

一个快捷函数 render() render------渲染

载入模板,填充上下文,再返回由它生成的HttpResponse对象

这是一个非常常见的操作流程,于是Django提供了一个快捷函数,我们用它来重写index()视图

python 复制代码
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)

此时,就不再需要导入loader和HttpResponse啦

4、抛出404错误

接下来我们来处理 投票详情页面------它会显示指定投票的问题标题

python 复制代码
from django.http import Http404
def detail(request,question_id):
    try:
        question=Question.objects.get(pk=question_id)
    except Question.DoesNotExist:#当指定问题ID所对应的问题不存在,这个视图就会抛出一个Http404错误
        raise Http404("Question does not exist")
    return render(request,"polls/detail.html",{"question":question})

一个快捷函数 get_object_or_404()

尝试用get函数来获取一个对象,如果不存在就抛出一个404错误

这是一个普遍的流程,Django也提供了一个快捷的函数,下面是修改的detail代码

python 复制代码
from django.shortcuts import get_object_or_404
def detail(request,question_id):
    question=get_object_or_404(Question,pk=question_id)
    return render(request,"polls/detail.html",{"question":question})

使用辅助函数 get_object_or_404,而不是自己捕获ObjectDoesNotExist异常?为什么模型API不直接抛出ObjectDoesNotExist,而是抛出Http404呢?

这样会增加 模型层 和 视图层 的 耦合性。但是指导Django设计的最重要的思想之一就是要 保证松散耦合。yi==一些受控的耦合会被包含在django.shortcuts模块中。

5、使用模板系统

在 polls/detail.html 中:

python 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Polls Details</title>
</head>
<body>
    <h1>{{question.question_text}}</h1>
    <ul>
        {% for choice in question.choice_set.all %}
            <li>{{ choice.choice_text }}</li>
        {% endfor %}
    </ul>
</body>
</html>

6、去除模板中的硬编码URL

在polls/index.html 中编写投票链接时,链接是硬编码

python 复制代码
 <li><a href="/polls/{{question.id}}/">{{question.question_text}}</a></li>

这种 硬编码、强耦合的方法的问题在于,在具有大量模板的项目中更改url变得更有挑战性。还记得在polls/urls模块中,path()函数中定义了name参数,你可以通过使用

{% url %} 模板标签来消除对url配置中定义的特定的URL路径的依赖

将其修改为:

python 复制代码
<li><a href="{% url"detail"question.id %}">{{question.question_text}}</a></li>

回忆一下在polls.urls中:

如果你想改变投票详情页面的url 比如想改成polls/specifics/12/,你不需要在模板里(包括其他模板),只要在polls/urls.py里稍微修改一下就行:

python 复制代码
path("specifics/<int:question_id>/",views.detail,name="detail"),

此时访问http://127.0.0.1:8000/polls/specifics/2/将看到

7、为URL名称添加命名空间

本教程中只有一个应用:polls,在实际中可能会有好几十个应用。那么如果两个应用出现重名的url时,Django怎么分辨呢?比如,polls应用有detail视图,另一个博客应用也有detail视图,Django如何知道 {% url %} 到底对应的是哪个应用呢,需要在两个地方做出声明:

1、在polls.urls中设置命名空间:

2、在模板标签处(index.html/a href)添加声明

相关推荐
威威猫的栗子20 分钟前
Python Turtle召唤童年:喜羊羊与灰太狼之懒羊羊绘画
开发语言·python
墨染风华不染尘1 小时前
python之开发笔记
开发语言·笔记·python
小技与小术1 小时前
数据库表设计范式
数据库·mysql
安迁岚1 小时前
【SQL Server】华中农业大学空间数据库实验报告 实验三 数据操作
运维·服务器·数据库·sql·mysql
安迁岚1 小时前
【SQL Server】华中农业大学空间数据库实验报告 实验九 触发器
数据库·sql·mysql·oracle·实验报告
Dxy12393102161 小时前
python bmp图片转jpg
python
Loganer1 小时前
MongoDB分片集群搭建
数据库·mongodb
麦麦大数据1 小时前
Python棉花病虫害图谱系统CNN识别+AI问答知识neo4j vue+flask深度学习神经网络可视化
人工智能·python·深度学习
LKID体1 小时前
Python操作neo4j库py2neo使用之创建和查询(二)
数据库·python·neo4j
LKID体1 小时前
Python操作neo4j库py2neo使用之py2neo 删除及事务相关操作(三)
开发语言·python·neo4j