一、图片验证
参考文档: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中