慕学在线--3、知识点一

一、图片验证

参考文档:http://django-simple-captcha.readthedocs.io/en/latest/usage.html
下载地址:https://github.com/mbi/django-simple-captcha

  1. 在类中定义CaptchaField

    from captcha.fields import CaptchaField
    class RegisterForm(forms.Form):
        email = forms.EmailField(required=True)
        password = forms.CharField(required=True, min_length=5)
        captcha = CaptchaField(error_messages={'invalid': u'验证码错误', })   # invlid 返回错误信息提示,因为invalid值默认显示为英文
  2. 在view.py文件,判断验证是否通过,与其它form校验一样

    from  django.contrib.auth.hashers import make_password
    class RegisterView(View):
        def post(self,request):
            registerform = RegisterForm(request.POST)     # form验证
            if registerform.is_valid():  判断校验是否通过
                email=request.POST('email','')
                password=request.POST('password','')
                userprofile=UserProfile()    #创建一个userprofile的实例
                userprofile.username=email
                userprofile.email=email
                userprofile.password=make_password(password)   #对明文密码进行加密保存,数据库中存储的密码是密文
                userprofile.save()
            else:
                return render(request, 'register.html', {
                    'registerform': registerform,    # 将registerform加载到页面
                })  # 返回登录页面,加载错误信息
  3. 在html页面使用registerform信息,与其它form验证一样

    <div class=" {% if forgetpwd_form.errors.captcha %}errorput{% endif %}">  # 如果验证码错误信息dict中包含captcha键值对
                <label>验&nbsp;证&nbsp;码</label>
                {{ forgetpwd_form.captcha }}   # 显示验证码
           </div>

二、邮箱验证

  1. settings.py配置邮箱

    EMAIL_HOST = 'smtp.sina.com'
    EMAIL_PORT = 25
    EMAIL_HOST_USER = 'qd_ltf@sina.com'  # 登录用户
    EMAIL_HOST_PASSWORD = 'litaifa001'
    EMAIL_FROM = 'qd_ltf@sina.com'  # 指明发件人,应与邮件登录用户保持一致
    EMAIL_USE_TLS = False
  2. models.py设计数据表

    
    # -*- coding: utf-8 -*-
    
    from __future__ import unicode_literals
    from datetime import datetime
    from django.db import models
    class EmailVerifyRecord(models.Model):
        email = models.EmailField(verbose_name=u'邮箱', max_length=50)
        code = models.CharField(verbose_name=u'验证码', max_length=20)
        send_type = models.CharField(verbose_name=u'发送类型', choices=(('register', u'注册'), ('forget', u'忘记'), ('update', u'更改邮箱')),max_length=10)
        send_time = models.DateTimeField(verbose_name=u'发送时间', default=datetime.now)
        class Meta:
            verbose_name = u'邮箱验证记录'
            verbose_name_plural = verbose_name
        def __unicode__(self):
            return self.email
  3. 定义邮件发送函数

    from random import Random
    from django.core.mail import send_mail
    
    # 引入全局变量
    
    from mxonline2.settings import EMAIL_FROM
    from .models import EmailVerifyRecord
    
    def send_verify_email(to_email, subject, message, send_type='register', from_email=EMAIL_FROM):
     # 生成随机字符串,以便用户激活时进行比对
     code = random_str(16)
     message = message+code+r'/'+to_email+r'/'
     email_record = EmailVerifyRecord()
     email_record.email = to_email
     email_record.code = code
     email_record.send_type = send_type
     # 将发送的邮件code保存到数据库,以便在激活时比对
     email_record.save()
     send_status = send_mail(recipient_list=[to_email], subject=subject, message=message, from_email=from_email )
     return send_status
    
    
    # 生成随机字符串
    
    def random_str(random_len=8):
     chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxy"
     chars_len = len(chars) - 1
     rand_str = ''
     random = Random()
     while random_len > 0:
         rand_str += chars[random.randint(0, chars_len)]
         random_len -= 1
     return rand_str
  4. 在views.py中发送邮件

     class XXXXView(View):
     def post(self, request):
                 send_status = send_verify_email(
                     to_email=email,
                     subject=u'慕学在线网激活与注册',
                     message=u'请点击链接完成慕学在线网的激活 http://127.0.0.1:8000/active/',
                     send_type='register'
                 )
                 if send_status:
                     return render(request, 'login.html', {})

三、修改密码

  1. 配置url

    \# 修改密码
    url(r'^update/pwd/$', UpdatePwdView.as_view(), name='update_pwd'),
  2. 定义form

    class ModifyPwdForm(forms.Form):
        password1 = forms.CharField(required=True, min_length=5)
        password2 = forms.CharField(required=True, min_length=5)
  3. 定义view

    class UpdatePwdView(LoginRequiredMixin,View):
        def post(self,request):
            pwd1=request.POST.get('password1')
            pwd2=request.POST.get('password2')
            if not pwd1 == pwd2:
                return HttpResponse(json.dumps({'status':'fail','msg':u'两次输入密码不一致'}),content_type='application/json')
            modify_form=ModifyPwdForm(request.POST)
            if not modify_form.is_valid():
                HttpResponse(json.dumps(modify_form.errors), content_type='application/json')  # 将错误信息dict,转化为json,此处需要根据js代码而进行调整
    
            user_profile=request.user    # password在dango中是加密的方式存放,所以,需要将pwd1加密后存放;如果需要验证用户输入的密码是否正确,不能直接比较,需要用user = authenticate(username=username, password=password)  判断user返回是否是非None
            user_profile.password=make_password(pwd1)  
            user_profile.save()
    
            return HttpResponse(json.dumps({'status': 'success', }), content_type='application/json')
  4. html文件

    <div class="resetpwdbox dialogbox" id="jsResetDialog">
       <h1>修改密码</h1>
       <div class="close jsCloseDialog"><img src="{% static '' %}images/dig_close.png"/></div>
       <div class="cont">
    
           <form id="jsResetPwdForm" autocomplete="off">
               <div class="box">
                   <span class="word2">新&nbsp;&nbsp;密&nbsp;&nbsp;码</span>
                   <input type="password" id="pwd" name="password1" placeholder="6-20位非中文字符"/>
               </div>
               <div class="box">
                   <span class="word2">确定密码</span>
                   <input type="password" id="repwd" name="password2" placeholder="6-20位非中文字符"/>
               </div>
               <div class="error btns" id="jsResetPwdTips"></div>
               <div class="button">
                   <input id="jsResetPwdBtn" type="button" value="提交"/>
               </div>
               {% csrf_token %}
           </form>
       </div>
    </div>
  5. js代码

    $(function(){
        //个人资料修改密码
        $('#jsUserResetPwd').on('click', function(){
            Dml.fun.showDialog('#jsResetDialog', '#jsResetPwdTips');
        });
    
        $('#jsResetPwdBtn').click(function(){
            $.ajax({
                cache: false,
                type: "POST",
                dataType:'json',
                url:"/user_center/update/pwd/",    # 如果js文件是由外部引入,不能使用动态{% url ' ' %%}
                data:$('#jsResetPwdForm').serialize(),
                async: true,
                success: function(data) {
                    if(data.password1){
                        Dml.fun.showValidateError($("#pwd"), data.password1);   # 此处可通过将request.errors信息转化为json传入
                    }else if(data.password2){
                        Dml.fun.showValidateError($("#repwd"), data.password2);
                    }else if(data.status == "success"){
                        Dml.fun.showTipsDialog({
                            title:'提交成功',
                            h2:'修改密码成功,请重新登录!',
                        });
                        Dml.fun.winReload();
                    }else if(data.msg){
                        Dml.fun.showValidateError($("#pwd"), data.msg);
                        Dml.fun.showValidateError($("#repwd"), data.msg);
                    }
                },
                errors:function (data) {
                    alert('error')
                }
            });
        });

四、电话号码校验

电话号码校验,对字段进行更深层次的自定义封装,

class UserAskModelForm(forms.ModelForm):  # 继承forms.ModelForm,而不是 forms.Form ModelForm的使用实例
    class Meta:
        model = UserAsk  # Model类  # 需要form校验的字段,此处字段名应与form表单提交的input的name保持一致
        fields = ['name', 'mobile', 'coursename']    

    def clean_mobile(self):  # 对字段进行更深一层的自定义封装 ,固定写法
        mobile = self.cleaned_data['mobile']  # 取出mobile字段的值。cleaned_data为一个字典型数据
        reg_mobile = "^1[358]\d{9}$|^147\d{8}$|^176\d{8}$"   # 手机号码匹配正则表达式
        p = re.compile(reg_mobile)   # p为re对象
        if p.match(mobile):   # 能正确匹配
            return mobile  # 根据需要还可以返回其它值
        else:
            raise forms.ValidationError(u'手机号码非法', code='mobileInvalid')  # 抛出错误异常

五、分页功能

相关文档:https://github.com/jamespacileo/django-pure-pagination
一、文档主要内容
Installation

Install package from PYPI:
pip install django-pure-pagination

or clone and install from repository:
git clone git@github.com:jamespacileo/django-pure-pagination.git
cd django-pure-pagination
python setup.py install


Add pure_pagination to INSTALLED_APPS
INSTALLED_APPS = (
    ...
    'pure_pagination',
)

Finally substitute from django.core.paginator import Paginator with from pure_pagination import Paginator

Settings

A few settings can be set within settings.py     #  默认值,可以不设置
PAGINATION_SETTINGS = {    
    'PAGE_RANGE_DISPLAYED': 10,
    'MARGIN_PAGES_DISPLAYED': 2,

    'SHOW_FIRST_PAGE_WHEN_INVALID': True,
}

PAGE_RANGE_DISPLAYED is the number of pages neighbouring the current page which will be displayed (default is 10)
MARGIN_PAGES_DISPLAYED is the number of pages neighbouring the first and last page which will be displayed (default is 2)
Set SHOW_FIRST_PAGE_WHEN_INVALID to True when you want to just show first page when provided invalid page instead of 404 error

Usage example

Following is a simple example for function based views. For generic class-based views, see bellow.
view file: views.py

from django.shortcuts import render_to_response
from pure_pagination import Paginator, EmptyPage, PageNotAnInteger

def index(request):
    try:
        page = request.GET.get('page', 1)
    except PageNotAnInteger:
        page = 1

    objects = ['john', 'edward', 'josh', 'frank']

    # Provide Paginator with the request object for complete querystring generation

    p = Paginator(objects, per_page=5, request=request)   # 此处说明文档有错误,request默认为none

    people = p.page(page)

    return render_to_response('index.html', {
        'people': people,
    }

template file: index.html

{# index.html #}
{% extends 'base.html' %}

{% block content %}

{% for person in people.object_list %}    # 此处应修改
    <div>
        First name: {{ person }}
    </div>
{% endfor %}

{# The following renders the pagination html #}
<div id="pagination">
    {{ people.render }}    # 此方法,html样式不可控
</div>
{% endblock %}

Usage
There a few different way you can make use of the features introduced within django-pure-pagination.
Easiest way to render the pagination is to call the render method i.e. {{ page.render }}
Alternatively you can access the Page object low level methods yourself
Special note: page_obj and current_page both point to the page object within the template.

{% load i18n %}
<div class="pagination">
    {% if page_obj.has_previous %}   # 如果当前页有前一页,则显示上一页,否则不显示上一页
            <a href="?{{ page_obj.previous_page_number.querystring }}" class="prev">&lsaquo;&lsaquo; {% trans "previous" %}</a>
    {% else %}
        <span class="disabled prev">&lsaquo;&lsaquo; {% trans "previous" %}</span>
    {% endif %}

    {% for page in page_obj.pages %}   # 对所有页面进行循环显示
        {% if page %}
            {% ifequal page page_obj.number %}
                <span class="current page">{{ page }}</span>
            {% else %}
                <a href="?{{ page.querystring }}" class="page">{{ page }}</a>
            {% endifequal %}
        {% else %}
            ...
        {% endif %}
    {% endfor %}
    {% if page_obj.has_next %}
        <a href="?{{ page_obj.next_page_number.querystring }}" class="next">{% trans "next" %} &rsaquo;&rsaquo;</a>
    {% else %}
        <span class="disabled next">{% trans "next" %} &rsaquo;&rsaquo;</span>
    {% endif %}
</div>

Generic Class-Based Views
Documentation for Django generic class-based views on https://docs.djangoproject.com/en/dev/ref/class-based-views/

  • views.py
from django.views.generic import ListView
from pure_pagination.mixins import PaginationMixin
from my_app.models import MyModel
class MyModelListView(PaginationMixin, ListView):
    # Important, this tells the ListView class we are paginating
    paginate_by = 10

    # Replace it for your model or use the queryset attribute instead
    object = MyModel

template files:
Note that the Django generic-based list view will include the object page_obj in the context. More information on https://docs.djangoproject.com/en/dev/ref/generic-views/#list-detail-generic-views

  • _pagination.html
{% load i18n %}
<div class="pagination">
    {% if page_obj.has_previous %}
        <a href="?{{ page_obj.previous_page_number.querystring }}" class="prev">&lsaquo;&lsaquo; {% trans "previous" %}</a>
    {% else %}
        <span class="disabled prev">&lsaquo;&lsaquo; {% trans "previous" %}</span>
    {% endif %}
    {% for page in page_obj.pages %}
        {% if page %}
            {% ifequal page page_obj.number %}
                <span class="current page">{{ page }}</span>
            {% else %}
                <a href="?{{ page.querystring }}" class="page">{{ page }}</a>
            {% endifequal %}
        {% else %}
            ...
        {% endif %}
    {% endfor %}
    {% if page_obj.has_next %}
        <a href="?{{ page_obj.next_page_number.querystring }}" class="next">{% trans "next" %} &rsaquo;&rsaquo;</a>
    {% else %}
        <span class="disabled next">{% trans "next" %} &rsaquo;&rsaquo;</span>
    {% endif %}
</div>
  • my_app/myobject_list.html
{# my_app/myobject_list.html #}
{% extends 'base.html' %}

{% block content %}

{% for object in object_list %}
    <div>
        First name: {{ object.first_name }}
    </div>
{% endfor %}

{# The following renders the pagination html #}
{% include "_pagination.html" %}

{% endblock %}

二、应用案例

  1. 定义包含分页html代码的文件 _pagination.html # 相关css文件参照慕学在线案例

    ```
    <div class="pageturn">
        <ul class="pagelist">
            {% if page_obj.has_previous %}    # 只需要传统参数page_obj
                <li class="long"><a href="?{{ page_obj.previous_page_number.querystring }}">上一页</a></li>
            {% endif %}
    
            {% for page in page_obj.pages %}
                {% if page %}
                    {% ifequal page page_obj.number %}
                        <li class="active"><a href="" class="page">{{ page }}</a></li>
                    {% else %}
                        <li><a href="?{{ page.querystring }}" class="page">{{ page }}</a></li>
                    {% endifequal %}
                {% else %}
                    ...
                {% endif %}
            {% endfor %}
    
            {% if page_obj.has_next %}
                <li class="long"><a href="?{{ page_obj.next_page_number.querystring }}">下一页</a></li>
            {% endif %}
        </ul>
    </div>
    
    # 注意:
    {% for teacher in page_obj.object_list %}  # 对page_obj对象遍历时,需要取page_obj.object_list
    
    ```
    
  2. 在html文件中插入 {% include ‘_pagination.html’ %}

    {% include '_pagination.html' %}
  3. 在views.py文件中传入数据page_obj

    all_course = all_course.order_by('-' + order_by)
    
    try:
        page = request.GET.get('page', 1)
    except PageNotAnInteger:
        page = 1  # 保证page不为空
    p = Paginator(all_course, 3, request=request)   # 3 表示每页3个对象
    page_obj = p.page(page)
    
    
    # page_obj=all_course
    
    
    return render(request, 'course-list.html', {
        'page_obj': page_obj,
        'hot_course': hot_course,
        'order_by': order_by,
    })

六、404及500页面

  1. urls.py中配置

    handler404 = 'user_profile.views.page_not_found'
    handler500 = 'user_profile.views.page_error'
  2. 编写函数

    def page_not_found(request):
        # 全局404处理函数
        from django.shortcuts import render_to_response
        response = render_to_response('404.html', {})
        response.status_code = 404
        return response
    
    def page_error(request):
        # 全局500页面处理函数,500错误主要指的是服务器端的错误,如程序中出现:print 1/0
        from django.shortcuts import render_to_response
        response = render_to_response('500.html', {})
        response.status_code = 500
        return response
  3. 修改测试

    • urls.py文件修改

      urlpatterns = [
      .....
          # 配置静态文件,404 测试用
          url(r'^static/(?P<path>.*)$', serve, {"document_root": STATIC_ROOT}),
      ....
    • settings.py文件修改

      DEBUG = True
      DEBUG = False  # 测试404 用
      
      ALLOWED_HOSTS = []
      ALLOWED_HOSTS = ['*']  # 测试404 用
      
      STATIC_ROOT = os.path.join(BASE_DIR, 'static')  # 静态文件根目录(测试404用)

七、django与ajax

例:有Form表单

  1. html文件中form表单

    <form class="rightform" id="jsStayForm">
        <div>
            <img src="{% static 'images/rightform1.png' %}"/>
            <input type="text" name="name" id="companyName" placeholder="名字" maxlength="25"/>
        </div>
        <div>
            <img src="{% static 'images/rightform2.png' %}"/>
            <input type="text" name="mobile" id="companyMobile" placeholder="联系电话"/>
        </div>
        <div>
            <img src="{% static 'images/rightform3.png' %}"/>
            <input type="text" name="coursename" id="companyAddress" placeholder="课程名" maxlength="50"/>
        </div>
        <p class="error company-tips" id="jsCompanyTips"></p>
        <input class="btn" type="text" id="jsStayBtn" value="立即咨询 >"/>
        {% csrf_token %}
    </form>
  2. html文件中ajax函数

     <script>
          $(function () {
              $('#jsStayBtn').on('click', function () {
                  $.ajax({
                      cache: false,   #  
                      type: "POST",  # 类型,POST或GET,默认为GET
                      url: "{% url 'org:user_ask' %}",  #发送请求的地址
                      data: $('#jsStayForm').serialize(),  #是一个对象,连同请求发送到服务的数据
                      async: true,# 预期服务器返回的数据类型。如果不指定,jQ将自动根据HTTP包MINME信息来智能判断,一般我们采用json格式,可以设置为
                      dataType:json # 是一个方法,请求成功后的回调函数,传入返回后的数据,以及包含成功代码的字符串,此处data与前面标绿色的data不同
                      success: function (data) { 
                          if (data.status) {
                              $('#jsStayForm')[0].reset();
                              alert("提交成功")
                          }
                          else {
                              $('#jsCompanyTips').html(data.msg)
                          }
                      },
                      error: function (data) {  # 是一个方法,请求失败时调用此函数。传入XMLHttpRequest对象
                          alert('error');
                      }
                  });
              });
          })
    
      </script>
  3. view文件中返回json

    import json
    from django.http import HttpResponse
    class UserAskView(View):
        def post(self, request):
    ......
            json_dict = {'status': True}   # 需要根据需要设置
    
    # 需要用json.dumps 将dict 转换成str
    
            return HttpResponse(json.dumps(json_dict), content_type="application/json")
    又如:return HttpResponse(json.dumps(user_info.errors),content_type='application/json')

例:无Form表单,收藏

  1. html文件中收藏元素

    <div class="btn fr collectionbtn notlogin" data-favid="22" data-fav-type="1">
             {% if has_fav %}已收藏{% else %}收藏{% endif %}  # 保证页面刷新后仍正确显示
     </div>
  2. html文件中ajax函数

    // add fav
    function add_fav(current_elem, fav_id, fav_type) {
        $.ajax({              # ajax  的第一个参数,字典
            cache: false,
            type: "POST",
            url: "{% url 'org:add_fav' %}",
            data: {'fav_id': fav_id, 'fav_type': fav_type},
            async: true,
            beforeSend: function (xhr, settings) {    # 需要添加csrf_token
                xhr.setRequestHeader("X-CSRFToken", "{{ csrf_token }}");  # 添加csrf_token
            },
            success: function (data) {      # ajax  的第二个参数,回调函数
                if (data.status == 'fail') {
                    if (data.msg == '用户未登录') {
                        window.location.href = "login.html";
                    } else {
                        alert(data.msg)
                    }
                } else if (data.status == 'success') {
                    current_elem.text(data.msg)
                }
            },
            error:function (data) {    # ajax  的第三个参数,回调函数
                alert('error')
            },
        });
    }
    
    // click add fav
    $('.collectionbtn').on('click', function () {              # 点击触发
        add_fav($(this), {{ org.id }}, 'organization');    # 参数
    });
  3. view文件中返回json

    class AddFavView(View):
    def post(self, request):
        # 检查用户是否登录
        user = request.user  #  无论用户是否登录,request 都有一个user对象
        if not user.is_authenticated:     # 检查用户是判断登录
            return HttpResponse(json.dumps({'status': 'fail', 'msg': u'用户未登录'}), content_type='application/json')
    
        fav_id = request.POST.get('fav_id', '0')
        fav_type = request.POST.get('fav_type', '')
        fav_record = UserFavorite.objects.filter(userprofile=user, favid=int(fav_id), favtype=fav_type)
        # 如果有户已收藏,则取消收藏
        if fav_record:
            fav_record.delete()
            return HttpResponse(json.dumps({'status': 'success', 'msg': u'收藏'}), content_type='application/json')
    
        # 如果用户未收藏,则收藏
        user_fav = UserFavorite()
        user_fav.userprofile = user
        user_fav.favid = int(fav_id)
        user_fav.favtype = fav_type
        user_fav.save()
        return HttpResponse(json.dumps({'status': 'success', 'msg': u'已收藏'}), content_type='application/json')

八、课程播放页面

参考网站:http://videojs.com/getting-started/#customize

  1. 插入相应的js css

    <head>
      <link href="http://vjs.zencdn.net/5.8.8/video-js.css" rel="stylesheet">
    
      <!-- If you'd like to support IE8 -->
      <script src="http://vjs.zencdn.net/ie8/1.1.2/videojs-ie8.min.js"></script>
    </head>
    
    <body>
      <video id="my-video" class="video-js" controls preload="auto" width="640" height="264"
      poster="MY_VIDEO_POSTER.jpg" data-setup="{}">
        <source src="{{ video.url }}" type='video/mp4'>
        <source src="{{ video.url }}" type='video/webm'>
        <p class="vjs-no-js">
          To view this video please enable JavaScript, and consider upgrading to a web browser that
          <a href="http://videojs.com/html5-video-support/" target="_blank">supports HTML5 video</a>
        </p>
      </video>
    
      <script src="http://vjs.zencdn.net/5.8.8/video.js"></script>
    </body>
  2. 将数据上传到七牛云,相应会生成url外链
    这里写图片描述

  3. 将外链保存到数据库存的url中

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值