零基础使用Django2.0.1打造在线教育网站

零基础使用Django2.0.1打造在线教育网站(十七):我要学

2018-08-09  本文已影响43人  啃饼小白

写在前面

本篇笔记我们将介绍我要学习小页面的配置,为什么需要单独介绍,是因为这个和其他页面的耦合度不是很高,单独写一篇便于今后学习的需要。

本篇笔记对应于第十七篇代码,对应于github的位置是https://github.com/licheetools/eduline

配置我要学习

这就是我要学习的页面,它是通过Ajax来控制的,也就是异步的javascript和xml。它可以在保证当前页面不被重新刷新的条件下,提交表单向后台传送数据。



正如你在前面所学习的那样,但凡涉及到了表单的提交都会有一个form验证。我们仿照前面的逻辑在operation应用下面新建一个forms.py文件,用于此处表单的验证。

然后在里面添加如下代码:


from django import forms


class UserAskForm(forms.Form):
    name = forms.CharField(required=True, min_length=2, max_length=20)
    mobile = forms.CharField(required=True, min_length=11, max_length=11)
    course_name = forms.CharField(required=True, min_length=5, max_length=50)
就是这个样子:
接着打开operation/models.py文件,发现这两个函数定义的字段信息非常相似,连要求都是一样的:
那么我们就有一个疑问,如何让代码重复利用,不需要再次重新造轮子呢?我们可以利用Django自带的ModelForm,这比form强大多了,除了继承现有的字段还可以新增字段!新增代码如下:
# 进阶版的函数
class AnotherUserAskForm(forms.ModelForm):
    # 除了继承现有的字段还可以新增字段
    class Meta:
        model = UserAsk
        # 自定义需要验证的字段
        fields = ["name", "mobile", "course_name"]
就是这个样子: 接下来的一步就是path的配置了,现在有一个疑问,就是我们的项目url文件,已经存放了很多url,如果我们再往里面新增url就很容易造成管理上的混乱:

我们在思考能不能像高考考场一样,有许多分考场,学生在各个分考场的试卷会送到省里,在保证考试有效的情况下,避免人员来往市区的麻烦。Django里面其实也是有的,所以我们就采用include的机制,来达到这个目的:在保证path的有效情况下,将各个app应用的path分开放置,最后将app的path引入项目的path就可以了。下面我们开始在organization应用下面,新建urls.py文件,里面增加如下代码:

from django.urls import path, include, re_path
from .views import OrgView


urlpatterns = [
    # 课程机构列表页url
    path("list/", OrgView.as_view(), name="org_list"),
]

然后回到我们的eduline/urls.py文件,我们将刚才的那行path用下面的一行include代码替换掉:

# 课程机构应用path配置
    path("org/", include('organization.urls', namespace="org")),

注意: namespace是命名空间,可以防止因名字重复而导致发生错误。
就是这个样子:

我们运行一下我们的项目,发现报错了:
Specifying a namespace in include() without providing an app_name ' 
 django.core.exceptions.ImproperlyConfigured: Specifying a namespace in 
 include() without providing an app_name is not supported. Set the app_name 
 attribute in the included module, or pass a 2-tuple containing the list of 
 patterns and app_name instead.

错误上说我们没有写上app的名字,所以我们需要在各个app的urls.py文件里面加上各个app_name:app_name = "organization"就是这个样子:

然后重启我们的项目,在浏览器地址栏输入http://127.0.0.1:8000/org/list然后回车,发现和我们之前的页面一样。不知道你注意到没有,现在我们输入的是http://127.0.0.1:8000/org/list而不是之前的http://127.0.0.1:8000/org_list。也就是说,现在我们所有的关于课程机构的url都是在org这个分页面之下的,其实这个org就是我们之前在项目urls中配置的organization的分path的一个总名字。

为了验证我们的操作是否有问题,我们采用点击页面中课程机构列表来查看当前页面是不是没有变化(没有变化是正常的,因为指向同一个url)。首先我们需要打开base.html页面,在里面ctrl+F 搜索授课机构,将所在一行的代码修改如下:

<li class="active" ><a href="{% url 'org:org_list' %}">授课机构</a></li>

然后运行我们的项目,在浏览器地址栏输入http://127.0.0.1:8000/org/list然后回车,出现这个页面,再点击页面中课程机构列表,发现还是这个页面,确实是这样,我们的配置没有问题:

继续Ajax配置

前面说到我要学习的页面,它是通过Ajax来控制的,是一种异步加载方式,所以我们此时不能在view里面直接render一个页面回来,应该是给前端返回json数据,而不是页面。这里我们就要用到HttpResponse这个类,它指明了给用户返回哪种类型的数据。

打开organization/views.py文件,在里面添加如下代码:

from operation.forms import AnotherUserAskForm

# 我要学习功能实现
class AddUserAskView(View):
    def post(self, request):
        userask_form = AnotherUserAskForm(request.POST)
        # 判断form是否有效
        if userask_form.is_valid():
            #  注意modelform和form的区别,modelform它有model的属性,而且有个参数commit,当它为真时会把数据存入到数据库
            user_ask = userask_form.save(commit=True)

            # 如果保存成功,则返回json,不过后面必须有content_type用于告诉浏览器返回的类型
            return HttpResponse("{'status': 'success'}", content_type='application/json')
        else:
            # 如果保存失败,则返回json,并将form的错误信息通过msg传递到前端进行显示
            return HttpResponse("{'status': 'fail', 'msg':{0}}".format(userask_form.errors),  content_type='application/json')

接着打开organization/urls.py文件,我们配置path,在里面添加如下代码:

from .views import AddUserAskView

# 用户咨询配置url
    path("add_ask/", AddUserAskView.as_view(), name="add_ask"),

然后打开org-list.html页面,在最底下新添加如下Ajax代码:

{% block custom_js %}
    <script>
    $(function(){
        $('#jsStayBtn').on('click', function(){
            $.ajax({
                cache: false,
                type: "POST",
                url:"{% url 'org:add_ask' %}",
                data:$('#jsStayForm').serialize(),
                async: true,
                success: function(data) {
                    if (data.status == 'success'){
                        $('#jsStayForm')[0].reset();
                        alert("提交成功")
                    }else if (data.status == 'fail'){
                        $('#jsCompanyTips').html(data.msg)
                    }
                },
            });
        });
    })

</script>
{% endblock %}

这个是Ajax代码,熟悉javascript的小伙伴们肯定很好理解,$(function(){})是程序入口,这里面其实就是通过DOM(文本对象模型)来控制节点,从而达到控制节点树的目的。我们是通过监听id为jsStayBtn的按钮来实现对数据的控制,当用户点击了这个按钮,就会触发url跳转,如果成功则继续调用data函数,它有两个状态:成功和失败,分别对应不同的提示信息。这里就不详细介绍了。别忘记在form表单提交加上{% csrf_token %}

现在我们测试一下我们的项目,在图示位置打上断点,开启DeBug模式:


在前端页面输入信息:

再打开数据库,查看operation_userask这个数据表,发现数据已经保存成功了:
不知道细心地你发现没有,我刚才电话号码输了:12306,页面提示是手机号,所以必须是11位,因此这里必须加上手机号码的合法性验证。

打开我们的operation/forms.py文件,里面加上如下代码:

import re

# 验证手机号码是否合法
    def clean_mobile(self):
        mobile = self.cleaned_data["mobile"]
        REGEX_MOBILE = "^1[358]\d{9}$|^147\d{8}$|^176\d{8}$"
        p = re.compile(REGEX_MOBILE)
        if p.match(mobile):
            return mobile
        else:
            raise forms.ValidationError("手机号码非法", code="mobile_invalid")

关于正则表达式的用法,大家可以关注我的另一个专题《趣玩Python爬虫》,我目前在筹划中,预计9月份就会更新了。

接下来你可以重复刚才的测试操作,看手机号码验证是否生效了,这里就不一一演示了。

至此,我们关于我要学习的小页面的配置就到此为止了,感谢你的赏阅。下一篇笔记,我们就介绍课程机构的详情页面的配置了。

本篇笔记对应于第十七篇代码,对应于github的位置是https://github.com/licheetools/eduline

上一篇下一篇

猜你喜欢

热点阅读