Django框架学习 - 创建视图

视图简介

视图在Django中的作用是用于处理Web请求信息以及返回响应信息的函数。
当我们访问http://127.0.0.1:8000/polls时,Django会解析出'polls'这个路径,然后拿着这个路径去URLconfs里配置相对应的视图函数,视图函数接收请求,然后处理请求,最后返回响应信息,也许这一段不是很理解,但是当做完之后再回头看,就很清楚了。

投票应用,需要列以下几个视图:

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

创建视图

增加视图

我们通过编辑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)

其中request属性,当一个页面被请求时,Django就会创建一个包含本次请求信息的HttpRequest对象,Django会将这个对象自动传递给视图函数,一般约定使用request参数来接收这个对象,在视图函数中,可以通过访问该对象的属性来提取http协议的的请求数据,以下是常用的属性,也可以查看【官网】中详细说明

request.GET:url上携带的参数,包含所有HTTP GET参数的类字典对象QueryDict
request.POST:post请求携带的数据,包含所有HTTP POST参数的类字典对象QueryDict
request.method:请求方法,请求中使用的HTTP方法的字符串表示,全大写(POST/GET)
request.path:完整路径
request.path_info:URL的路径 不包含ip和端口 不包含参数
request.body:请求体

配置URLconfs

我们通过上面增加了polls/views.py的内容,但是我们还不能马上使用,因为当我们去访问的时候,Django并不能通过URL找到对应的视图函数,所以,我要在URLconfs里增加新增视图函数的路由,那来编辑一下polls/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'),
]

保存,重新运行Django。当然,我们可以根据上面路径上的注释来测试访问一下,即http://127.0.0.1:8000/polls/34http://127.0.0.1:8000/polls/34/resultshttp://127.0.0.1:8000/polls/34/vote,其实很简单的,是视图中question_id在接收path中的<int:question_id>,如果你不能清楚也没关系,后续将内容添加后,可以帮助更容易的理解。

使用视图

结合polls这个项目,我们给polls/views.py中的index视图函数进行修改一下,利用数据库API来查询和展示前五个投票问题

from django.http import HttpResponse
from .models import Question


def index(request):
    # 利用数据库API来获取前五个问题
    latest_question_list = Question.objects.order_by('-pub_date')[:5]
    # 将内容提取出来,使用','符号拼接起来
    output = ', '.join([q.question_text for q in latest_question_list])
    # 使用HttpResponse返回拼接后的内容
    return HttpResponse(output)

创建静态文件

上面的代码可以展示前五个问题,但是这时的展示是没有经过渲染的,所以我们给它们加上模板文件进行渲染,Django中提供了对应的寻找目录,即在polls下创建一个template文件夹,再在这个文件夹下创建一个polls的文件夹,最后在这个文件里创建index.html文件,完整的路径就是polls/template/polls/index.html,这个是在setting.py文件中TEMPLATES选项设置的。

然后,我们可以将以下内容,填充到刚创建的模板文件(polls/template/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来使用模板渲染

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

from .models import Question


def index(request):
    # 利用数据库API来获取前五个问题
    latest_question_list = Question.objects.order_by('-pub_date')[:5]
    # 指定渲染使用的模板
    template = loader.get_template('polls/index.html')
    # 指定问题列表
    context = {
        'latest_question_list': latest_question_list,
    }
    # 将问题列表传到模板中,然后通过HttpResponse返回响应
    return HttpResponse(template.render(context, request))

快捷函数:render()

以上代码中,载入模板-填充模板上下文-生成HttpResponse对象,这一套流程使用太过于频繁,所以Django提供了一个render()函数来减少冗余,我们把上面的代码通过render()来重写

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)

抛出404

访问404,也是很常用的一个操作,当我们访问不存在的一个问题ID时,就抛出404异常

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

# ...
def detail(request, question_id):
    try:
        question = Question.objects.get(pk=question_id)
    except Qestion.DoesNotExist:
        raise Http404("Question does not exist.")
    return render(request, 'polls/detail.html', {'question': question})
# ...

此时,这个detail视图使用到了一个模板文件,但是我们没有创建,所以现在无法正常运行,我们先创建一个,进行占位,即polls/template/polls/detail.html

{{ question }}

快捷函数:get_object_or_404()

尝试使用get()函数获取一个对象,如果不存在就抛出Http404异常也是一个普遍的流程,对此,Django也提供了一个快捷函数,所以我们利用这个快捷函数来修改一个detail视图

from django.shortcuts import get_object_or_404, render
from .model import Question

# ...
def detail(request, question_id):
    question = get_object_or_404(Question, pk=question_id)
    return render(request, 'polls/detail.html', {'question': 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 }}
{ % for % }循环中发生的函数调用:question.choice_set.all被解释为Python代码中的question.choice_set.all(),将会返回一个可迭代的Choice对象,这个对象被for循环输出

去除硬编码

向上翻,可以看到polls/index.html中的投票链接是硬链接

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

这个问题在于,硬链接和强耦合相链接,对于一个包含多个应用的项目,修改起来比较复杂,所以我们可以使用在polls/urls.py中为URL定义的name参数来替代原有的硬链接,使用{ % url %}来使用

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

URL命名空间

命名空间的作用是,区分多个应用时,{% url %}中name参数对应哪条URL,修改比较简单,就是在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/index.html文件

<li><a href="{% url 'polls:detail' question.id %}">{{ question.question_text }}</a></li>
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 196,165评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,503评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,295评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,589评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,439评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,342评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,749评论 3 387
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,397评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,700评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,740评论 2 313
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,523评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,364评论 3 314
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,755评论 3 300
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,024评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,297评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,721评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,918评论 2 336

推荐阅读更多精彩内容