前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >零基础使用Django2.0.1打造在线教育网站(十七):我要学习配置

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

原创
作者头像
啃饼思录
修改2018-09-10 21:38:09
6820
修改2018-09-10 21:38:09
举报

关于博主

努力与运动兼备~~~有任何问题可以加我好友或者关注微信公众号,欢迎交流,我们一起进步!

代码语言:txt
复制
                 微信公众号:  啃饼思录
代码语言:txt
复制
                 QQ: 2810706745(啃饼小白)

写在前面

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

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

配置我要学习

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

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

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

代码语言:txt
复制
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强大多了,除了继承现有的字段还可以新增字段!新增代码如下:

代码语言:txt
复制
# 进阶版的函数
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文件,里面增加如下代码:

代码语言:txt
复制
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代码替换掉:

代码语言:txt
复制
# 课程机构应用path配置
    path("org/", include('organization.urls', namespace="org")),

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

就是这个样子:

我们运行一下我们的项目,发现报错了:

代码语言:txt
复制
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"就是这个样子:

然后重启我们的项目,在浏览器地址栏输入

代码语言:txt
复制
http://127.0.0.1:8000/org/list

然后回车,发现和我们之前的页面一样。不知道你注意到没有,现在我们输入的是

代码语言:txt
复制
http://127.0.0.1:8000/org/list

而不是之前的

代码语言:txt
复制
http://127.0.0.1:8000/org_list

也就是说,现在我们所有的关于课程机构的url都是在org这个分页面之下的,其实这个org就是我们之前在项目urls中配置的organization的分path的一个总名字。

为了验证我们的操作是否有问题,我们采用点击页面中课程机构列表来查看当前页面是不是没有变化(没有变化是正常的,因为指向同一个url)。首先我们需要打开base.html页面,在里面ctrl+F 搜索授课机构,将所在一行的代码修改如下:
代码语言:txt
复制
<li class="active" ><a href="{% url 'org:org_list' %}">授课机构</a></li>

然后运行我们的项目,在浏览器地址栏输入

代码语言:txt
复制
http://127.0.0.1:8000/org/list
然后回车,出现这个页面,再点击页面中课程机构列表,发现还是这个页面,确实是这样,我们的配置没有问题:

继续Ajax配置

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

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

代码语言:txt
复制
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,在里面添加如下代码:

代码语言:txt
复制
from .views import AddUserAskView

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

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

代码语言:txt
复制
{% 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文件,里面加上如下代码:

代码语言:txt
复制
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

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 关于博主
  • 写在前面
  • 配置我要学习
    • 继续Ajax配置
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档