一、圖片驗證
參考文檔:http://django-simple-captcha.readthedocs.io/en/latest/usage.html
下載地址:https://github.com/mbi/django-simple-captcha
在類中定義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值默認顯示爲英文
在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加載到頁面 }) # 返回登錄頁面,加載錯誤信息
在html頁面使用registerform信息,與其它form驗證一樣
<div class=" {% if forgetpwd_form.errors.captcha %}errorput{% endif %}"> # 如果驗證碼錯誤信息dict中包含captcha鍵值對 <label>驗 證 碼</label> {{ forgetpwd_form.captcha }} # 顯示驗證碼 </div>
二、郵箱驗證
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
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
定義郵件發送函數
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
在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', {})
三、修改密碼
配置url
\# 修改密碼 url(r'^update/pwd/$', UpdatePwdView.as_view(), name='update_pwd'),
定義form
class ModifyPwdForm(forms.Form): password1 = forms.CharField(required=True, min_length=5) password2 = forms.CharField(required=True, min_length=5)
定義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')
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">新 密 碼</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>
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">‹‹ {% trans "previous" %}</a>
{% else %}
<span class="disabled prev">‹‹ {% 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" %} ››</a>
{% else %}
<span class="disabled next">{% trans "next" %} ››</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">‹‹ {% trans "previous" %}</a>
{% else %}
<span class="disabled prev">‹‹ {% 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" %} ››</a>
{% else %}
<span class="disabled next">{% trans "next" %} ››</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 %}
二、應用案例
定義包含分頁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 ```
在html文件中插入 {% include ‘_pagination.html’ %}
{% include '_pagination.html' %}
在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頁面
urls.py中配置
handler404 = 'user_profile.views.page_not_found' handler500 = 'user_profile.views.page_error'
編寫函數
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
修改測試
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表單
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>
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>
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表單,收藏
html文件中收藏元素
<div class="btn fr collectionbtn notlogin" data-favid="22" data-fav-type="1"> {% if has_fav %}已收藏{% else %}收藏{% endif %} # 保證頁面刷新後仍正確顯示 </div>
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'); # 參數 });
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
插入相應的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>
將數據上傳到七牛雲,相應會生成url外鏈
將外鏈保存到數據庫存的url中