Django学习官方文档-第三部分

版权声明:笔记随便写写 https://blog.csdn.net/aaxin_666/article/details/86539637

概况

Django 中的视图的概念是「一类具有相同功能和模板的网页的集合」。这里我认为就是网页,不管是哪种。
都要经过视图函数的处理,
而在我们的投票应用中,我们需要下列几个视图:

问题索引页——展示最近的几个投票问题。
问题详情页——展示某个投票的问题和不带结果的选项列表。
问题结果页——展示某个投票的结果。
投票处理器——用于响应用户为某个问题的特定选项投票的操作。

在 Django 中,网页和其他内容都是从视图派生而来。每一个视图表现为一个简单的 Python 函数(或者说方法,如果是在基于类的视图里的话)。Django 将会根据用户请求的 URL 来选择使用哪个视图(更准确的说,是根据 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 模式映射到视图

编写视图函数

前面说过,视图函数接收请求,返回相关的页面给浏览器。现在让我们向 vote/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)

这将会直接返回内容到页面上,
把这些视图添加到url里面,现在需要打开urls.py

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'),
]

path里面的参数已经说过了,现在开启Django的服务器,开启浏览器’/vote/45’,就会显示相对应的页面,

当某人请求你网站的某一页面时——比如说, "/vote/34/" ,Django 将会载入 mysite.urls 模块,因为这在配置项 ROOT_URLCONF 中设置了。然后 Django 寻找名为 urlpatterns 变量并且按序匹配正则表达式。在找到匹配项 'vote/',它切掉了匹配的文本("vote/"),将剩余文本——"34/",发送至 'vote.urls' URLconf 做进一步处理。在这里剩余文本匹配了 '<int:question_id>/',使得我们 Django 以如下形式调用 detail():

在开始一个真正的视图的时候,我们应该在管理页面给每个问题加上选择,你还记得我们是怎么在管理页面添加问题的吗,打开admin.py,添加一行

admin.site.register(Choice)

这样,你打开管理页面,就会显示 添加选项的页面了,ps:在添加中文选项时,注意乱码问题,问题在于,你需要将choice_text字段的字符编码改成utf8,

写显示内容的视图

接下来的内容引用官方文档 //学累了
每个视图必须要做的只有两件事:返回一个包含被请求页面内容的 HttpResponse 对象,或者抛出一个异常,比如 Http404 。至于你还想干些什么,随便你。

你的视图可以从数据库里读取记录,可以使用一个模板引擎(比如 Django 自带的,或者其他第三方的),可以生成一个 PDF 文件,可以输出一个 XML,创建一个 ZIP 文件,你可以做任何你想做的事,使用任何你想用的 Python 库。

Django 只要求返回的是一个 HttpResponse ,或者抛出一个异常。

因为 Django 自带的数据库 API 很方便,我们曾在 教程第 2 部分 中学过,所以我们试试在视图里使用它。我们在 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)

所以,去看一下数据库的API是非常有必要的,毕竟这是python——Django和数据库的交互
首先,在你的 polls 目录里创建一个 templates 目录。Django 将会在这个目录里查找模板文件。

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

在你刚刚创建的 templates 目录里,再创建一个目录vote,然后在其中新建一个文件 index.html 。换句话说,你的模板文件的路径应该是 vote/templates/polls/index.html 。因为 Django 会寻找到对应的 app_directories ,所以你只需要使用vote/index.html 就可以引用到这一模板了。
ps:这里要注意的是如果放在vote文件夹下面,没有问题,如果要与vote同级,那么你就必须要在setting.py 里面设置,在install-app这里的DIR修改为下

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

快捷函数

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)

这里的render函数,实现过程如下:

def my_render(request,template_path,context_dict={}):      #这里的方法和render方法是一样的
    #1.加载模板文件
    #2.定义模板上下文,给模板传递数据
    #3.模板渲染,产生一个替换后的HTML内容,render,
    '''还用模板文件'''
    temp = loader.get_template(template_path)

    context = RequestContext(request,context_dict)

    res_html = temp.render(context)

    return HttpResponse(res_html)

原理类似

错误

每个视图必须要做的只有两件事:返回一个包含被请求页面内容的 HttpResponse 对象,或者抛出一个异常,比如 Http404 。至于你还想干些什么,随便你
需要异常处理机制:

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不存在,会报错

再来一个快捷函数、

尝试用 get() 函数获取一个对象,如果不存在就抛出 Http404 错误也是一个普遍的流程。Django 也提供了一个快捷函数,下面是修改后的详情 detail() 视图代码:

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, 'vote/detail.html', {'question': question})

关于模板文件

模板变量

一般来说就是获取的数据库对象的变量,一般用{{}}来包裹

模板标签

就是一些python代码,需要用{%%},值得注意的是有开头部分就要有结尾部分,不然会报错。

模板过滤器

用在模板变量后面,用 | 链接,用于过滤一些不必要的数据,后面添加
过滤器

<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 对象使用字典查找(也就是使用 obj.get(str) 操作),如果失败了就尝试属性查找(也就是 obj.str 操作),结果是成功了。如果这一操作也失败的话,将会尝试列表查找(也就是 obj[int] 操作)。

在 {% for %} 循环中发生的函数调用:question.choice_set.all 被解释为 Python 代码 question.choice_set.all() ,将会返回一个可迭代的 Choice 对象,这一对象可以在 {% for %} 标签内部使用。

去除模板的硬编码

硬编码会增强耦合性,让代码变得更加复杂。还记得前面的path的第三参数吗?在这里派上用场了
例如:

<li><a href="/vote/{{ question.id }}/">{{ question.question_text }}</a></li>

可以改成:

<li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li>

这样不管你怎么更改网页的url,只需要在url.py 里面配置就可以了。

为url添加命名空间

教程项目只有一个应用vote 。在一个真实的 Django 项目中,可能会有五个,十个,二十个,甚至更多应用。Django 如何分辨重名的 URL 呢?举个例子,vote`` 应用有 detail 视图,可能另一个博客应用也有同名的视图。Django 如何知道 {% url %} 标签到底对应哪一个应用的 URL 呢?

答案是:在根 URLconf 中添加命名空间。在 vote/urls.py 文件中稍作修改,加上 app_name 设置命名空间:

from django.urls import path

from . import views

app_name = 'polls'
urlpatterns = [

再次修改:

<li><a href="{% url 'vote:detail' question.id %}">{{ question.question_text }}</a></li>

所以你们现在的网页情况是

在这里插入图片描述管理页面能够给问题添加选项,
在这里插入图片描述

现在,编写表格

在学习Django之前,你应当具备一些HTML和css的知识

<h1>{{ question.question_text }}</h1>

{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}

<form action="{% url 'vote:vote' question.id %}" method="post">
{% csrf_token %}
{% for choice in question.choice_set.all %}
    <input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}">
    <label for="choice{{ forloop.counter }}">{{ choice.choice_text }}</label><br>
{% endfor %}
<input type="submit" value="Vote">
</form>

简要说明:
上面的模板在 Question 的每个 Choice 前添加一个单选按钮。 每个单选按钮的 value 属性是对应的各个 Choice 的 ID。每个单选按钮的 name 是 “choice” 。这意味着,当有人选择一个单选按钮并提交表单提交时,它将发送一个 POST 数据 choice=# ,其中# 为选择的 Choice 的 ID。这是 HTML 表单的基本概念。
我们设置表单的 action 为 {% url ‘polls:vote’ question.id %} ,并设置 method=“post” 。使用 method="post"(与其相对的是method=“get”`)是非常重要的,因为这个提交表单的行为会改变服务器端的数据。 无论何时,当你需要创建一个改变服务器端数据的表单时,请使用 ``method=“post” 。这不是 Django 的特定技巧;这是优秀的网站开发技巧。
forloop.counter 指示 for 标签已经循环多少次。
由于我们创建一个 POST 表单(它具有修改数据的作用),所以我们需要小心跨站点请求伪造。 谢天谢地,你不必太过担心,因为 Django 已经拥有一个用来防御它的非常容易使用的系统。 简而言之,所有针对内部 URL 的 POST 表单都应该使用 {% csrf_token %} 模板标签。

{% csrf_token %} 模板标签

这个是为了防止跨域请求,而设置的,其本质是在设置了这个以后,服务器会发给浏览器一个编码,服务器本身保存一个,每次请求都会对比两者的值,如果对不上,就是禁止你访问。。
并不是绝对安全

now

from django.shortcuts import get_object_or_404, render
from django.urls import reverse

from .models import Choice, Question
# ...
def vote(request, question_id):
    question = get_object_or_404(Question, pk=question_id)
    try:
        selected_choice = question.choice_set.get(pk=request.POST['choice'])
    except (KeyError, Choice.DoesNotExist):
        # Redisplay the question voting form.
        return render(request, 'polls/detail.html', {
            'question': question,
            'error_message': "You didn't select a choice.",
        })
    else:
        selected_choice.votes += 1
        selected_choice.save()
        # Always return an HttpResponseRedirect after successfully dealing
        # with POST data. This prevents data from being posted twice if a
        # user hits the Back button.
        return HttpResponseRedirect(reverse('polls:results', args=(question.id,)))

request.POST 是一个类字典对象,让你可以通过关键字的名字获取提交的数据。 这个例子中, request.POST[‘choice’] 以字符串形式返回选择的 Choice 的 ID。 request.POST 的值永远是字符串。

注意,Django 还以同样的方式提供 request.GET 用于访问 GET 数据 —— 但我们在代码中显式地使用 request.POST ,以保证数据只能通过 POST 调用改动。

如果在 request.POST[‘choice’] 数据中没有提供 choice , POST 将引发一个 KeyError 。上面的代码检查 KeyError ,如果没有给出 choice 将重新显示 Question 表单和一个错误信息。

在增加 Choice 的得票数之后,代码返回一个 HttpResponseRedirect 而不是常用的 HttpResponse 、 HttpResponseRedirect 只接收一个参数:用户将要被重定向的 URL(请继续看下去,我们将会解释如何构造这个例子中的 URL)。

As the Python comment above points out, you should always return an HttpResponseRedirect after successfully dealing with POST data. This tip isn’t specific to Django; it’s just good Web development practice.

在这个例子中,我们在 HttpResponseRedirect 的构造函数中使用 reverse() 函数。这个函数避免了我们在视图函数中硬编码 URL。它需要我们给出我们想要跳转的视图的名字和该视图所对应的 URL 模式中需要给该视图提供的参数。 在本例中,使用在 教程第 3 部分 中设定的 URLconf, reverse() 调用将返回一个这样的字符串:
ps:表单是post的提交方式,其中的数据也会以字典的形式保存在request【post】里面, name=“choice” id=“choice{{ forloop.counter }}” value="{{ choice.id }}" 这一句键是 ‘choice’,值是:choice.id

继续

views.py

from django.shortcuts import get_object_or_404, render


def results(request, question_id):
    question = get_object_or_404(Question, pk=question_id)
    return render(request, 'vote/results.html', {'question': question})

现在,创建一个 vote/results.html 模板:

<h1>{{ question.question_text }}</h1>

<ul>
{% for choice in question.choice_set.all %}
    <li>{{ choice.choice_text }} -- {{ choice.votes }} vote{{ choice.votes|pluralize }}</li>
{% endfor %}
</ul>

<a href="{% url 'polls:detail' question.id %}">Vote again?</a>

看出来什么吗?里面有一个模板过滤器
现在,在你的浏览器中访问 /vote1/ 然后为 Question 投票。你应该看到一个投票结果页面,并且在你每次投票之后都会更新。 如果你提交时没有选择任何 Choice,你应该看到错误信息。如下图
在这里插入图片描述
在这里插入图片描述

ps

有人说过:你学过什么,就记下什么,记下什么,就上传什么.
只是当做笔记,

猜你喜欢

转载自blog.csdn.net/aaxin_666/article/details/86539637