慕學在線--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中

發佈了40 篇原創文章 · 獲贊 6 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章