Django学习3
views是一个面向public的接口,它是项目中提供特定功能的页面。在Django中web的页面以及一些其他的内容都是通过view来表达,Django利用url的检查,拆分来选择views来显示。教程中的polls的项目需要如下几个views:
- Question索引:用来显示最近发布的Question。
- Question详情:显示Question的内容以及可以投票的表单。
- Question结果:显示当前的Question的投票结果。
- 投票动作:为Question投票。
关于urls的全部用法课参见 url dispather
step1:view练习
我们之前已经在polls/views.py中创建了一个index的views,现在继续添加如下的views:
#这里%s是python的新特性,甚至可以用元组来在一个地方插入数个string
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)
这里需要注意的就是%s的用法,具体在stackoverflow上 有解答。
完成了上述工作后就需要让这些views可以被使用,在polls/urls.py中可以增加如下代码让这些views能根据request被访问:
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'),
]
这样比如输入”127.0.0.1:8000/5”就会进入一个页面显示“You’re looking at question 5.”。在这< int:question_id >中< int:表示int类型来匹配question_id >表示定义被匹配的url字串的名字。
疑问
这样我有一个疑问就是如何确定到底有没有标号5的Question,这个问题应该会在后面解答。
step2:正式进入views的应用
在经过了上述的练习就大概知道了views的使用流程,下面可以针对polls这个应用写一些有意义的页面。
在此之前,需要知道的是view所做的工作无非是:一,返回一个HttpResponse;二,返回错误信息。并且view可以读取数据库信息,使用python模板,生成pdf等等功能,所以Django需要的只是HttpResponse,或者是错误信息。
接下来我们就在polls/views.py中重写index页面的view让它可以显示最新的5个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)
这里”’,’ . join([])“就是用,隔开list中的元素并组成字符串。
这样子完成后,输入/polls页面就会发现出现了最近创建的5个Question。但是这样用python写的页面设计并不是特别方便和美观,所以就要用到Django的template system。
那么首先需要在polls文件夹下创建一个名为templates的目录,然后再在templates层创建一个polls目录,而后在再polls下创建一个index.html,所以最终路径就是polls/templates/polls/index.html,这样保证了命名空间的独立性,保证和其他app有重名template也没有关系,并且由于内部template,可以直接用polls/index.html来使用。
而后在此文件中输入如下代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</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>
之后在polls/views.py中修改index的view代码:
from django.template import loader
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))
#也可以:return render(request, 'polls/index.html', context)
上述代码就是在view中加载了polls/index.html的代码并且将一个context传递给index.html而这个context就是一个字典,来表名在python中出现的object。
step3:a 404 error
那么使用404这个方法就可以解决我上面所说不能判断到底有没有这个请求的投票的问题。
在detail中可以去查找数据库,如果没有match到的记录,就给出404的界面,具体代码如下:
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})
#It can also work
'''
def detail(request, question_id):
question = get_object_or_404(Question, pk=question_id)
return render(request, 'polls/detail.html', {'question': question})
'''
/polls/templates/polls/detail.html页面代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>detail</title>
</head>
<body>
{{ question }}
</body>
</html>
这样每次都会去数据库检查是否有这个id的数据记录,利用try except来完成避免访问空的页面。在detail.html中可以简单的写一句{{question}}
就可以查看结果。
疑问
问什么可以直接使用{{question}}
就可以显示其中的内容,但是好像{{ question.question_text}}
也可以显示。
step4:使用template system
由于template的存在,所以就可以直接调用Question关联的choice,polls/templates/polls/detail.html代码如下:
<body>
<h1>{{ question.question_text }}</h1>
<ul>
{% for choice in question.choice_set.all %}
<li>
{{ choice.choice_text }}
</li>
{% endfor %}
</ul>
</body>
如上代码所示,tmeplate system利用”.”来引用属性,它会先去寻找object的字典树然后再去寻找它的属性,然后再去寻找它的索引。
step5:去除template中的hardcoded urls
在之前的index中我们使用了< a href = …的标签,其中我们是直接用”/polls/{ question.id}}/”来直接规定了link的指向,但是这样并不好,不方便修改。
我们可以将其改成如下形式:
<a href="{% url 'detail' question.id %}">{{ question.question_text }}</a>
这时候之前在urls.py中定义的name就有用了,以后如果想要改成如/polls/specifics/12/就可以直接在path中改成:
path('specifics/<int:question_id>/', views.detail, name='detail'),
step6:namespacing
在真正的项目中通常一个项目有多个app,这时候如果多个app都有detail view怎么办呢,这样之前所用的{% url %}
就分不清取用那个detail了。
所以在polls/urls.py中最顶上增加一条
app_name = 'polls'
然后将polls/templates/polls/index.html中的
<a href = "{% url 'detail' question.id %}>"
改成
< a href = "{% url 'pollls:detail' question.id" %}>