教程地址
做完Part4,再慢慢回顾,有以下两点是比较有感受的。
封装
在Part4中,我感受到了Django非常高的封装性,我个人觉得从一个学习者的角度出发,这是弊大于利的(比如我首次接触Django)
如果是以快速搭建一个网站为目的,节省开发周期和成本,那封装得越高越好,随手拿来用就是了,多么方便高效。
但是对于初学者,这虽然降低了了学习难度,但是增加了理解难度,也不太利于去拓展Web开发的深度。
- 举个例子
Django的内置表单对象,首先已经完成了表单验证的方方面面(比如非法字符限制,长度限制,非空,非通用密码判断),用户实体的封装,持久化等等。以下是UserCreationForm
的源码,可以看到这个还不是最核心的,更底层的在作为参数的
forms.ModelForm
中,这里就不贴了。
class UserCreationForm(forms.ModelForm):
"""
A form that creates a user, with no privileges, from the given username and
password.
"""
error_messages = {
'password_mismatch': _("The two password fields didn't match."),
}
password1 = forms.CharField(
label=_("Password"),
strip=False,
widget=forms.PasswordInput,
help_text=password_validation.password_validators_help_text_html(),
)
password2 = forms.CharField(
label=_("Password confirmation"),
widget=forms.PasswordInput,
strip=False,
help_text=_("Enter the same password as before, for verification."),
)
class Meta:
model = User
fields = ("username",)
field_classes = {'username': UsernameField}
def __init__(self, *args, **kwargs):
super(UserCreationForm, self).__init__(*args, **kwargs)
if self._meta.model.USERNAME_FIELD in self.fields:
self.fields[self._meta.model.USERNAME_FIELD].widget.attrs.update({'autofocus': True})
def clean_password2(self):
password1 = self.cleaned_data.get("password1")
password2 = self.cleaned_data.get("password2")
if password1 and password2 and password1 != password2:
raise forms.ValidationError(
self.error_messages['password_mismatch'],
code='password_mismatch',
)
self.instance.username = self.cleaned_data.get('username')
password_validation.validate_password(self.cleaned_data.get('password2'), self.instance)
return password2
def save(self, commit=True):
user = super(UserCreationForm, self).save(commit=False)
user.set_password(self.cleaned_data["password1"])
if commit:
user.save()
return user
看到这里我就有一个疑惑,Django作为一个后端框架,是将表单传到后台再进行验证,而这部分一般来说往往是通过客户端的Js来操作,Django这样不是很影响效率和浪费带宽吗?
在需要使用到邮箱字段时,教程引入了「继承」的概念,这里也出现了一出因为封装程度很高而引起的理解难点:
class SignUpForm(UserCreationForm):
email = forms.CharField(max_length=254, required=True, widget=forms.EmailInput())
class Meta:
model = User
fields = ('username', 'email', 'password1', 'password2')
考虑到代码的复用性以及耦合性,教程作者这里使用了fields = ('username', 'email', 'password1', 'password2')
,这很好
但是下面在控制器中:
def signup(request):
if request.method == 'POST':
form = SignUpForm(request.POST)
if form.is_valid():
user = form.save()
auth_login(request, user)
return redirect('home')
else:
form = SignUpForm()
return render(request, 'signup.html', {'form': form})
直接通过user = form.save()
获取了新对象,这很神奇。
测试
首先一点,测试系统会自动在任何以test开头的文件中寻找测试方法,当测试方法越来越多时,需要分模块来组织。
对于初学者来说,测试方法能看懂,也能理解其重要性,但是若要自己独立去写,是有一定难度的,首先是考虑不到那么周全,第二个是熟练度的问题。这需要锻炼。
比如以下几个用来检验返回值的api,就比较眼花缭乱了。
self.assertEquals()
//检查字符串
self.assertContains
//检查是否包含
self.assertIsInstance()
//检查对象类型
self.assertRedirects()
//检查是否重定向
self.assertTrue()
//检查是否为真
self.assertFalse()
//检查是否为假
等等
抛开其他优点,我觉得现阶段测试最直接的好处是:分批次测试,缩小寻找bug的内容,可以最直接地定位错误。而假如不用测试,在运行报错时,需要从一堆报错信息中去慢慢抽丝剥茧,反而影响效率。对测试地总结就是:磨刀不误砍柴工。
公众号:果核里的图灵<center>小白的探索之路</center>
网友评论