0. what
之前的笔记全部写在XX 云笔记里,当我在手机端打开 XX云笔记的时候,我发现看不到markdown笔记中的图片。显然这是因为我的截图都是本地的,没有上传到网络上,而上传的只是markdown的文本,所以手机端看不到相应的图片。其实作为客户端,XX应该开发一个自动上传图片的功能。
以前一直用XX云笔记写东西,特别是发现XX也有markdown以后,就在那里写的更多 了。前13次的笔记都在XX里,这里是找不到的。
今天继续之前的学习,该看Writing your first Django app, part 4了。
csdn的markdown使用起来还是要比**云笔记的体验好很多。
1. Write a simple form
对polls/detail.html进行一下升级
<h1>{{ question.question_text }}</h1>
{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}
<form action="{% url 'polls: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>
- 这段代码给每个choice添加了一个radio button,radio button的值为choice id;
- 使用post方法传递数据(相反,使用get方法得到数据)
- forloop.counter计数器
- 使用post方法时,要考虑Cross Site Request Forgeries,Django自带一种好用的防范系统,all POST forms that are targeted at internal URLs should use the {% csrf_token %} template tag。
上面的这段代码已经创建了一个没有实际功能的vote按键
之所以没有实际功能,当然是因为我们还没给他添加了。那么现在我们就在vote函数中用post方法来获取数据:
from django.http import HttpResponseRedirect, HttpResponse
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,)))
注意:如果你也和我一样不是复制粘贴,那在这段代码中特别注意最后一行args=(question.id,)
,千万不要丢了括号里的那个逗号呀!否则就是下面的结果。
当然即使你写对了,也还不是我们想要的样子,我们还没有写好results view。先改写一下results函数:
def results(request, question_id):
question = get_object_or_404(Question, pk=question_id)
return render(request, 'polls/results.html', {'question': question})
再创建一个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>
于是当你投票以后,就会出现结果页面了
下一步要学习的内容!
Avoiding race conditions using F()
2. Use generic views: Less code is better
- 根据URL中传入的参数,从数据库中获取数据
- 加载一个模板并返回渲染的模板
基于以上两点,Django提供一个简化的通用视图!
为了使用通用视图,我们需要对代码进行大幅调整
1. 修改URLconf
from django.conf.urls import url
from . import views
app_name = 'polls'
urlpatterns = [
url(r'^$', views.IndexView.as_view(), name='index'),
url(r'^(?P<pk>[0-9]+)/$', views.DetailView.as_view(), name='detail'),
url(r'^(?P<pk>[0-9]+)/results/$', views.ResultsView.as_view(), name='results'),
url(r'^(?P<question_id>[0-9]+)/vote/$', views.vote, name='vote'),
]
2. 修改views
from django.shortcuts import get_object_or_404, render
from django.http import HttpResponseRedirect
from django.urls import reverse
from django.views import generic
from .models import Choice, Question
class IndexView(generic.ListView):
template_name = 'polls/index.html'
context_object_name = 'latest_question_list'
def get_queryset(self):
"""Return the last five published questions."""
return Question.objects.order_by('-pub_date')[:5]
class DetailView(generic.DetailView):
model = Question
template_name = 'polls/detail.html'
class ResultsView(generic.DetailView):
model = Question
template_name = 'polls/results.html'
def vote(request, question_id):
... # same as above, no changes needed.