
教程:原文链接
两个重点概念:URLs 和 Forms
Tips:写Python一定要主义代码缩进,有些缩进问题是肉眼看不出来的。注意IndentationError,TabError
URLs
- 路由的几个参数辨析
- 路由的顺序问题,可能会导致无法检索
- 路由的正则表达式命名规范
- 比如:
url(r'^boards/(?P<pk>\d+)/$', views.board_topics, name='board_topics')
那么相应的控制器中:
def board_topics(request, pk):
# do something...
/d代表的是匹配整型,?P<pk>代表参数名使用规范的pk。当然也可以使用
url(r'^boards/(\d+)/$', views.board_topics, name='board_topics')
那么控制器中:
def board_topics(request, board_id):
# do something...
def board_topics(request, id):
# do something...
都可以,但是这不规范,不建议使用。
- 此外,文章谈及了命名规范中pk和id的区别,可见django框架设计中的一些细节。
- 关于页面之间的跳转,有些同学可能会被测试单元中的代码搞晕。其实并不复杂,如下:
<a href="{% url 'board_topics' board.pk %}">{{ board.name }}</a>
其中url应该是指明了urls.py中的entry,然后board_topics就是通过name值来寻找对应url,board.pk作为这条url的参数传入。
我们可以使用topics.html中的代码来印证上面的猜测:
<li class="breadcrumb-item"><a href="{% url 'home' %}">Boards</a></li>
其中name为home所对应的url不需要额外参数。
TESTs
setUp方法的使用。需要创建一个实体类来完成一系列的测试操作,因为测试环境使用的不是当前数据库而是一个全新的测试数据库。当完成所有测试时,这个测试数据库会被销毁。
注意每次修改业务代码后,都要进行测试。
TEMPLETEs
- 使用模板继承的时候遇到一个玄学问题。我明明已经将
{% extends 'base.html' %}放在html文件的顶部。
但是还是会抛出这个异常。如下:
django.template.exceptions.TemplateSyntaxError: <ExtendsNode: extends 'base.html'> must be the first tag in the template.
解决方法(#°Д°):

FORMs
Tips:
细节
防御跨站请求伪造:{% csrf_token %}
异常解决
-
首先来分析一下这个官方错误,虽然原文后续已经写了解决方法,但现实场景是大多数时候我们自己的代码出现异常时,往往没有这么直接针对性的解答教程,只能靠自己分析解决。
官方错误
第一个ERROR,最关键的是django.utils.datastructures.MultiValueDictKeyError: "'subject'",大致是在一个多值的字典里,一个名为subject的键出了问题。
回溯代码,发现可能出问题的应该在这里:
subject = request.POST['subject']
message = request.POST['message']
此时通过subject获取的值可能为空值或者是一些危险的注入或攻击。
第二个问题参考上述。
根据对上述两个问题的理解,可以快速找到问题所在,然后通过改造表单来修复。
- 第二个是我自己遇到的一个问题。在模仿了教程的测试代码后,运行出现这个错误。
ERROR: test_new_topic_valid_post_data (boards.tests.NewTopicTests)
----------------------------------------------------------------------
Traceback (most recent call last):
...
sqlite3.IntegrityError: NOT NULL constraint failed: boards_topic.starter_id
The above exception was the direct cause of the following exception:
...
django.db.utils.IntegrityError: NOT NULL constraint failed: boards_topic.starter_id
----------------------------------------------------------------------
Ran 10 tests in 0.152s
FAILED (errors=1)
可以理解为:
数据库字段的完整性错误:非空约束:boards_topic.starter_id
上述异常直接导致了下面的异常
django.db.utils.IntegrityError: NOT NULL constraint failed: boards_topic.starter_id
检查代码:
def new_topic(request,pk):
board =get_object_or_404(Board,pk=pk)
user=User.objects.first() #get currently logged in user
if request.method=='POST':
form =NewTopicForm(request.POST)
if form.is_valid():
topic=form.save(commit=False)
topic.board=board
topic.starter=user
topic.save()
post=Post.objects.create(
message=form.cleaned_data.get('message'),
topic=topic,
created_by=user
)
return redirect('board_topics',pk=board.pk)
else:
form=NewTopicForm()
return render(request, 'new_topic.html', {'board': board})
很疑惑,我已经将user设置为获取当前用户,然后将topic的starter设置为user,应该是没有问题的,但现实就是出错了,这个就是最纠结的时刻,头发基本都是因为这些掉的。
后来发现可能是测试代码中的问题。
def test_new_topic_valid_post_data(self):
url = reverse('new_topic', kwargs={'pk': 1})
data = {
'subject': 'Test title',
'message': 'Lorem ipsum dolor sit amet'
}
response = self.client.post(url, data)
self.assertTrue(Topic.objects.exists())
self.assertTrue(Post.objects.exists())
在测试的代码中提交的data中没有starter这个字段,而报错是starter.id具有非空约束,不能传空参进入。所以我觉得问题可能出在这里。然后我稍稍改造了测试方法,创建一个User对象并作为参数传入。
def test_new_topic_valid_post_data(self):
url = reverse('new_topic', kwargs={'pk': 1})
user1=User.objects.create(password='$R3n69v8eV3laNxBmKWCnVWfqOGYcNDOjAjHj2+EwUpc=')
data = {
'subject': 'Test title',
'message': 'Lorem ipsum dolor sit amet',
'starter': user1
}
response = self.client.post(url, data)
self.assertTrue(Topic.objects.exists())
self.assertTrue(Post.objects.exists())
此时再测试,显示通过:




