中间还有自动化测试和自定义CSS的部分被我先忽略了,最后一块是讲自定义admin后台的内容的.
代码同步在github上mysite-part5

开始

在一开始的时候,我们把Question引入了admin模块,如果我们需要对字段进行更改的话,可以在admin.py文件中自己来定义,比如字段的顺序:

1
2
3
class QuestionAdmin(admin.ModelAdmin):    
fields = ['pub_date', 'question_text']
admin.site.register(Question, QuestionAdmin)

这样就可以交换2个字段的位置了~

阅读全文 »

接着第三部分的内容继续app的开发.
代码同步在github上mysite-part4

写一个简单的表单

template/polls/detail.html来添加一个form表单:

1
2
3
4
5
6
7
8
9
10
<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>

解释

在form表单中,input标签的value值是被选择的question的id,对应的name名为choice,也就是说在选择了表单中的一个选项并且提交的时候,会向服务器发送一个POST请求,来表示哪一个choice被选择并且vote了.
**注意:**在向服务器提交表单的时候,使用POST请求是一个好的习惯
现在我们来实现views.py中的vote函数:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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,)))

解释

pk=request.POST['choice']这个参数表示,从request.POST请求中获取被选择的choice.
如果不存在的话,就抛出一个Choice.DoesNotExistChoice不存在的异常,错误信息为You didn’t select a choice..
如果存在的话,那么这个choice的votes属性增加1并且使用save()函数写入数据库中.
在完成数据库写入操作之后,向页面发送了一个HttpResponseRedirect,将网页重定向到polls的results上,并且带上了当前的question的id.
这个函数也等效为重定向到'polls/question.id/results'这个页面.
接着我们来完善一下results函数:

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

和resluts.html:

1
2
3
4
5
6
7
<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>

现在我们就已经完成了一个完整的查看问题并且投票然后查看投票信息的页面了~
接下来的操作只是对于代码的优化了.

使用通用视图

在我们之前写的代码中,有很多的步骤都是很重复但是又很简单的,比如从数据库获取信息,并且返回到页面,在django中,使用**通用视图(generic views)**来简化这些操作.
下面是修改的过程:

修改URL

polls/urls.py中,修改代码如下:

1
2
3
4
5
6
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'),
]

<question_id>换成了<pk>

修改views

polls/viwes.py文件修改如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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.

在这里使用了两个默认的视图:ListViewDetailView.和视图的名称一样,一个是返回对象的列表的视图,一个是详细信息的视图.

踩了个小坑

要把index.html中的detail改成polls:detail,不然会报错

  • DetailView使用pk来从URL中接受参数,所以在URLConfig中将question_id改成了pk

题目及理解

Given a List of words, return the words that can be typed using letters of alphabet on only one row’s of American keyboard like the image below.

Example 1:

1
2
Input: ["Hello", "Alaska", "Dad", "Peace"]
Output: ["Alaska", "Dad"]

Note:

  • You may use one character in the keyboard more than once.
  • You may assume the input string will only contain letters of alphabet.

理解

水题,题目的意思就是那些单词可以只用一行上的字母来生成.先以单词的第一个字母来确定属于哪一行,然后逐个判断后面的字母是不是这一行的就可以了.

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Solution {
public:
vector<string> findWords(vector<string>& words) {
vector<string> corr;
set<char> r1 = {'q','w','e','r','t','y','u','i','o','p'};
set<char> r2 = {'a','s','d','f','g','h','j','k','l'};
set<char> r3 = {'z','x','c','v','b','n','m'};
vector<set<char>> row = {r1,r2,r3};
for (int i=0; i<words.size(); i++){
int rows = 0;
for (int j=0;j<3;j++){
if (row[j].count(tolower(words[i][0])) > 0) rows = j;
continue;
}
corr.push_back(words[i]);
for (int k = 1; k <words[i].size(); k++){
if (row[rows].count(tolower(words[i][k])) == 0){
corr.pop_back();
break;
}
}
}
return corr;
}
};

其他的解法

Discuss里面也有很多很简短的代码的解法,基本上都是用到了正则表达式和过滤的结合,这里贴一个Python版的:

1
2
def findWords(self, words):    
return filter(re.compile('(?i)([qwertyuiop]*|[asdfghjkl]*|[zxcvbnm]*)$').match, words)

一行就解决了这个问题,正则还是强大啊~

0%