学习笔记:Django开发网上教育平台(参考了慕课网的教学视频)
第一步:进行环境的搭建(用到的IDE:pycharm ,数据库为mysql、nacicat、编辑语言python3.7、以及自己配置的虚拟环境venvpy37)
Django==2.2
配置好mysql数据库的连接
第二步就是需求分析和app的设计:
大致上分为 四个app(也就是四个模块,Django是按app来开发的)
- users--用户相关
- courese--课程相关
- organization--机构相关
- operation-用户操作相关
然后新建完app并调整好结构,静态文件的文件夹static,html页面的文件夹templates,媒体文件文件夹media等
因为系统自带的User表字段没有需要的字段所以自己新建覆盖了一张用户表来存储用户信息
django提供一种方式让我们可以重载它的类
继承AbstractUser
from datetime import datetime
from django.db import models
from django.contrib.auth.models import AbstractUser
GENDER_CHOICES=(
("male",'男'),
("female",'女')
)
class UserProfile(AbstractUser):
nick_name=models.CharField(max_length=50,verbose_name="昵称",default="")
birthday=models.DateField(verbose_name="生日",null=True,blank=True)
gender=models.CharField(verbose_name="性别",choices=GENDER_CHOICES,max_length=6)
address=models.CharField(max_length=100,verbose_name="地址",default="")
mobile=models.CharField(max_length=11,verbose_name="手机号码")
image=models.ImageField(verbose_name="用户头像",upload_to="head_image/%Y/%m",default="default.jpg")
class Meta:
verbose_name="用户信息"
verbose_name_plural=verbose_name
def __str__(self):
if self.nick_name:
return self.nick_name
else:
return self.username
在模型文件里设计好之后,需要在全局文件里设置
AUTH_USER_MODEL="users.UserProfile",让系统知道用的是这张表
运行makemigrations和migrate 生成迁移文件和表
还有coures相关的表:课程表、章节、视频、课程资源 四个表
organizations:城市表、课程机构表、讲师表
operations:用户咨询表、课程评论表、用户收藏表、用户信息表、用户课程表
代码太多就不详细贴上去了
在设计过程种使用了分层设计 避免循环导入不同app中的model
配置好相关的path 路径
然后用xadmin来搭建后台管理系统:在github上搜索xadmin下载
1. 下载xadmin源码
2. 在settings的INSTALLED_APPS中添加
crispy_forms 和 xadmin
3. 安装xadmin的依赖包
django-crispy-forms
django-import-export
django-reversion
django-formtools
future
httplib2
six
xlwt
xlsxwriter
requests这些依赖包都要安装到虚拟环境中(进入虚拟环境后进入安装的文件夹路径 pip install -r ruquirements.txt 读取需要的依赖包并全部安装)
4. 通过migrate生成xadmin需要的表
然后配置好urls.py的路径
import xadmin
path('xadmin/', xadmin.site.urls),
使用xadmin 可以自己识别用户自己定义的表
这样的情况下后台照样把我们自己定义的User识别进去了,它会帮我们自动注册进来
然后在之前新建好的每个app里 新建adminx.py文件 配置后台 例如:course app
import xadmin
from apps.courses.models import Course,Lesson,Video,CourseResource
class GlobalSettings(object):
#配置后台的标题和标尾
site_title="林鹏项目--后台管理系统"
site_footer="林鹏项目"
menu_style="accordion"
class BaseSettings(object):
#配置后台主题
enable_themes = True
use_bootswatch = True
class CourseAdmin(object):
list_display = ["id", "name","detail","desc","degree","learn_times","students"]
search_fields = ["name","detail","desc","degree"]
list_filter = ["name", "desc", "learn_times","teacher__name"]
list_editable = ["degree", "desc"]
class LessonAdmin(object):
list_display = ["course", "name", "learn_times"]
search_fields = ["course", "name"]
list_filter = ["course__name", "name", "learn_times"]
list_editable = ["name"]
class VideoAdmin(object):
list_display = ["lesson", "name", "learn_times", "url"]
search_fields = ["lesson", "name"]
list_filter = ["name", "desc", "learn_times"]
list_editable = ["lesson", "name"]
class CourseResourceAdmin(object):
list_display = ["course", "name", "file"]
search_fields = ["course", "name", "file"]
list_filter = ["course", "name", "file"]
list_editable = ["course", "name"]
xadmin.site.register(Course,CourseAdmin)
xadmin.site.register(Lesson,LessonAdmin)
xadmin.site.register(Video,VideoAdmin)
xadmin.site.register(CourseResource,CourseResourceAdmin)
#xadmin全局设置
xadmin.site.register(xadmin.views.CommAdminView,GlobalSettings)
xadmin.site.register(xadmin.views.BaseAdminView,BaseSettings)
这里包括了列表、过滤 、搜索、编辑框的功能 list_display 为列表 search-fields 搜索列 list_filter 过滤 list_editable 编辑框
接下来就是开始第一个功能的编写:登录
在做登录之前需要配置好首页和登录页面
然后编写逻辑函数 在views.py文件
使用的是CBV的逻辑来开发
CBV-class base view(优点:
class是可以继承的 为了后期便于维护有利于代码重用
)
因为是登录所以和用户相关是在users这个app里的views里编写
class LoginView(View):
def get(self,request, *args, **kwargs):
#判断用户是否登录 是否登录的状态is_authenticated在django2.o之后版本都是属性如果是登录状态则重定向到首页
if request.user.is_authenticated:
return HttpResponseRedirect(reverse("index"))
login_form=DynamicLoginForm()
return render(request,"login.html",{
"login_form":login_form
})
def post(self,request, *args, **kwargs):
#表单验证
login_form=LoginForm(request.POST)
if login_form.is_valid():
user_name=login_form.cleaned_data["username"]
password=login_form.cleaned_data["password"]
# 用于通过用户名和密码查询用户是否存在
user = authenticate(username=user_name, password=password)
if user is not None:
#查询到用户
login(request,user)
#login方法会自动登录,request为上面django传递的参数
#登录成功之后返回页面
return HttpResponseRedirect(reverse("index"))
else:
# 未查询到用户
return render(request, "login.html", {"msg": "用户名或密码错误","login_form":login_form})
else:
return render(request,"login.html",{"login_form":login_form})
这里的代码逻辑 全部备注好了: 登陆页面有两种请求 一种是提交的post 一种是get
request.user.is_authenticated: 这句话是判断是否登陆,如果有就重定向到首页,login_form牵涉到表单验证的内容,
user_name=login_form.cleaned_data["username"]
password=login_form.cleaned_data["password"]是获取到表单清洗后的值[]里的值是html页面 input标签的name属性的值,这两行就是获取前段页面提交的数据
然后下面就是逻辑判断 ,判断用户是否存在 存在就登陆,用django 内部的login方法
否则就返回错误信息,并返回表单验证的错误信息
<div class="error btns login-form-tips" id="jsLoginTips">{% if login_form.errors %}{% for key,error in login_form.errors.items %}{{ error }}{% endfor %}{% else %}{{ msg }}{% endif %}
这是前端页面的判断逻辑,
{% if login_form.errors %}意思为如果表单中存在错误,
{% for key,error in login_form.errors.items %}{{ error }}:for key 是哪个字段 ,error in login_form.errors.items是错误类型 , {{ error }}是输出错误结果
{% else %}{{ msg }}:否则输出msg
这里的判断逻辑是:如果在表单验证中发现用户名或者密码错误:将前端样式的输入框变成红色
在表单提交的时候出现403错误是因为django 内部的安全验证 防止跨域攻击只需要在表单的</form>
之前插入这句就行了
{% csrf_token %}
登陆开发完了之后:就是开发退出登陆的借口
编写的View函数都是继承django 本身自带的view
编写一个LogoutView(View)
class LogoutView(View):
def get(self,request, *args, **kwargs):
logout(request)
return HttpResponseRedirect(reverse("index"))
然后再urls.py中修改一下配置
path('logout/', LogoutView.as_view(),name="logout"),
然后就是在html页面配置退出的url
<a class="fr" href="{% url 'logout' %}">退出</a>
这里的url 都是这样的书写格式 和前面的path 的name属性 一直 它会自动识别出路径 而且方便后期维护,只需要改动path的url路径名
接下来还学习了一种用手机验证码来登陆的功能以及注册:
首先为了能够发送手机验证码,需要找有发送手机短信资质的运营商 ,这里使用的是云片网 (具体如何注册使用就不说明了)
在云片网:www.yunpian.com
此时准备完之后就需要在pycharm中编写代码了:
在apps文件夹下新建一个目录为utils 专门存放这种工具类文件
查看API文档有步骤说明
我们短信验证只需要用到单条短信发送 进入相关的文档说明里
这是相关的参数,只需选择3个必传参数即可 其他参数看需求
apikey 在控制台里
apikey 最好在项目的全局设置里配置好 方便后期更改
短信发送需要用到request
import requests
import json
def send_single_sms(apikey,code,mobile):
#发送单条短信
url="https://sms.yunpian.com/v2/sms/single_send.json"
text="【林鹏先生】您的验证码是{}".format(code)
res = requests.post(url, data={
"apikey":apikey,
"mobile":mobile,
"text":text
})
re_json=json.loads(res.text)
return re_json
if __name__ == "__main__":
res=send_single_sms("f3444e2cea8176e2a16aad30ddc4af19","test","13587701643")
import json
res_json=json.loads(res.text)
code=res_json["code"]
msg=res_json["msg"]
if code==0:
print("发送成功")
else:
print("发送失败:{}".format(msg))
print(res.text)
这里的if __name__== "__main__"
用来测试的
这里的url 为文档说明中的url, text 为云片网审核通过的模板样式
有了url 和text 之后就是发送数据了:
通过request的post方法 一个参数为url 一个参数为data data为dict形式
dict里面的值为文档里面要传的参数
这样就算完成了,但是还需要用ajax的方式来完成短信验证码的发送用到了js的知识
$.ajax({
cache: false,
type: 'post',
dataType:'json',
url:"/send_sms/",
data:{
mobile:$inpRegMobile.val(),
"captcha_1":$inpRegCaptcha.val(),
"captcha_0":$('#id_captcha_0').val(),
},
class SendSmsView(View):
def post(self, request, *args, **kwargs):
send_sms_form = DynamicLoginForm(request.POST)
re_dict={}
if send_sms_form.is_valid():
mobile=send_sms_form.cleaned_data["mobile"]
#随机生成数字验证码
code=generate_random(4,0)
re_json=send_single_sms(yp_apikey,code,mobile=mobile,)#这个是json数据用于交互
if re_json["code"] == 0:
re_dict["status"] = "success"
r=redis.Redis(host=REDIS_HOST,port=REDIS_PORT,db=0,charset="utf8",decode_responses=True)
r.set(str(mobile),code)#set模式 可以持久化
r.expire(str(mobile),60*5)#设置验证码5分钟过期
else:
re_dict["msg"]= re_json["msg"]
else:
for key,value in send_sms_form.errors.items():
#如果出错 哪个字段出错,错误原因是什么 表单验证之后errors每个key 它的错误信息是list形式
re_dict[key]=value[0]
return JsonResponse(re_dict)
这里return不用rander 而是用JsonResponse 因为这里是用ajax 异步发送短信此时,上面提到的403错误不能再用
{% csrf_token %}来解决了
因为原本用form表单提交的方式只需要在form标签 里加入{% csrf_token %}即可 浏览器会帮我们直接表单里的所有值
但是我们使用ajax异步的方式来进行方式 这样浏览器就不会帮我们提交上去
所有使用{% csrf_token %} 并没有用
此时就用到csrf_exempt() 让服务器不验证csrf
此时思考一下 如果在js文件里面 添加csrf_token 获取这个值是否可以???但是在html页面点击查看源码可以看出值并没有赋值进来 所以这个方法行不通
这里还牵涉到了redis来记录发送的数据
通过云片网发送验证码之后 这个验证码我们得保存起来 进行验证
所以保存数据:第一种 就是保存在数据库 另一种就是保存在内存中
用存在内存的方式 有两个问题:
1. 重启django之后,变量不存在了
2.随着验证码越来越多,,内存占用越来越大,验证码过期处理
用数据库可以实现 但是有特殊情况 发送完验证码之后用户并没有进行后续操作 这样数据就会越来越多
此时用 redis k-v数据库
(redis要运行起来 redis-server.exe redis-cli.exe)
import redis
if re_json["code"] == 0:
re_dict["status"] = "success"
r=redis.Redis(host=REDIS_HOST,port=REDIS_PORT,db=0,charset="utf8",decode_responses=True)
r.set(str(mobile),code)#set模式 可以持久化
r.expire(str(mobile),60*5)#设置验证码5分钟过期
把redis的对象取出来赋给r,然后r.set 模式来持久化
同时验证码还需要一个验证逻辑,我们使用表单来验证 这个验证码和发送的验证码是否一致
class DynamicLoginPostForm(forms.Form):
mobile = forms.CharField(required=True,min_length=11,max_length=11)
code = forms.CharField(min_length=4,max_length=4,required=True)
def clean_code(self):
mobile = self.data.get("mobile")
code = self.data.get("code")
# 取出这两个值之后就是涉及到在redis中查询了
r = redis.Redis(host=REDIS_HOST, port=REDIS_PORT, db=0, charset="utf8", decode_responses=True)
redis_code = r.get(str(mobile))
# 然后比较两个code值
if code != redis_code:
raise forms.ValidationError("验证码不正确")
# 如果正确直接返回
return code
把redis对象取出来之后查询它的code值 和 表单提交的code 进行比较 如果不相等抛出异常
这里的抛出异常我们用 raise
如果正确就返回这个code
:
还需要动态验证码:
在github上搜索 django-captcha-simple 里面有安装和配置步骤
然后文档会告诉如何使用,按照步骤我们创建一个表单
class DynamicLoginForm(forms.Form):
#这是动态验证码和短信的表单
mobile =forms.CharField(required=True,min_length=11,max_length=11)
captcha = CaptchaField()
有了这个表单之后在views.py里面我们把表单里的传递过去 ,并显示到前段页面
<div class="form-group marb20 blur" id="jsRefreshCode">
{{ login_form.captcha }}
{{ dynamic_form.captcha }}
</div>
这里的两个只会显示其中一个不会冲突
这样动态验证码就实现了
接下来就是配置前段的html的url 和逻辑判断
所有的配置完了之后不要忘记配置urls.py文件的路径
动态登陆的逻辑完了之后需要实现动态注册的功能:
class RegisterView(View):
def get(self, request, *args, **kwargs):
register_get_form=RegisterGetForm()
return render(request,"register.html",{
"register_get_form":register_get_form
})
def post(self, request, *args, **kwargs):
register_post_form = RegisterPostForm(request.POST)
if register_post_form.is_valid():
# 如果验证通过说明不存在用户,要新建
mobile = register_post_form.cleaned_data["mobile"]
password = register_post_form.cleaned_data["password"]
#新建用户
user = UserProfile(username=mobile)
# 因为数据库里的密码是加密后的 所以不能直接存储明文密码需要通过set_password加密
user.set_password(password)
user.mobile = mobile
user.save()
login(request, user)
return HttpResponseRedirect(reverse("index"))
else:
register_get_form = RegisterGetForm()
return render(request, "register.html.html", {
"register_get_form":register_get_form,
"register_post_form":register_post_form,
})
注册页面也有两个请求 1个是get 1个post ,get 请求需要获取到注册页面的动态验证码
post 请求是要把前段提交的数据存储,但是有两个判断逻辑,第一个是用户没有注册,这个比较简单把用户提交的数据存储到数据库里面, 第二个逻辑是用户已经注册过了,此时需要用到表单验证,专门验证mobile这个字段时候存在
class RegisterPostForm(forms.Form):
mobile = forms.CharField(required=True, min_length=11, max_length=11)
code = forms.CharField(min_length=4, max_length=4, required=True)
password = forms.CharField(min_length=4)
def clean_mobile(self):
mobile = self.data.get("mobile")
# 验证手机号码是否注册过
users=UserProfile.objects.filter(mobile=mobile)
if users:
raise forms.ValidationError("该手机号码已注册")
return mobile
def clean_code(self):
mobile = self.data.get("mobile")
code = self.data.get("code")
# 取出这两个值之后就是涉及到在redis中查询了
r = redis.Redis(host=REDIS_HOST, port=REDIS_PORT, db=0, charset="utf8", decode_responses=True)
redis_code = r.get(str(mobile))
# 然后比较两个code值
if code != redis_code:
raise forms.ValidationError("验证码不正确")
# 如果正确直接返回
return code
然后注意前段页面的配置:
form表单的方法要是post方法 action属性值为{% url 'register'%}这种形式
input标签的name属性的值要和view函数里一一对应 并且注意403错误 在表单里加入 {%csrf_token%}
然后就是错误信息判断完的显示,和之前在做登陆的时候一样
学习笔记:Django开发网上教育平台(参考了慕课网的教学视频)的更多相关文章
- Django:学习笔记(1)——开发环境配置
Django:学习笔记(1)——开发环境配置 Django的安装与配置 安装Django 首先,我们可以执行python -m django --version命令,查看是否已安装django. 如果 ...
- django+xadmin在线教育平台(五)
3-3 django orm介绍与model设计 上节教程完成后代码(来学习本节前置条件): 对应commit: 留言板前端页面展示.本次内容截止教程3-2结束. 可能现在你还在通过手写sql语句来操 ...
- django+xadmin在线教育平台(四)
3-2 配置表单页面 必要的该说的,该了解的 前置条件: 你已经学习了前面教程.将项目的文件夹目录结构,setting配置等修改完毕与我保持一致. 本节通过Django快速的配置一个留言板页面来学习 ...
- django开发微信公众平台遇到的问题记录
在pythonanywhere.com上使用django开发微信公众平台应用,结果用户发送的信息,微信服务器一次也没有成功转发到pythonanywhere上来,但是用接口测试工具调试却发现是正常的, ...
- VSTO学习笔记(三) 开发Office 2010 64位COM加载项
原文:VSTO学习笔记(三) 开发Office 2010 64位COM加载项 一.加载项简介 Office提供了多种用于扩展Office应用程序功能的模式,常见的有: 1.Office 自动化程序(A ...
- Aurora学习笔记连载一:仿真平台搭建
由于公司项目需要,需要学习Aurora协议,才有了这样的连载学习笔记,也算是对自己学习的一份记录吧. 对于Aurora是什么,大家自行百度. 当然,Kevin也在此先提醒大家,本套学习笔记不是你想学就 ...
- python学习笔记--Django入门四 管理站点--二
接上一节 python学习笔记--Django入门四 管理站点 设置字段可选 编辑Book模块在email字段上加上blank=True,指定email字段为可选,代码如下: class Autho ...
- Android:日常学习笔记(8)———开发微信聊天界面
Android:日常学习笔记(8)———开发微信聊天界面 只做Nine-Patch图片 Nine-Patch是一种被特殊处理过的PNG图片,能够指定哪些区域可以被拉升,哪些区域不可以.
- django开发环境搭建(参考流程)
django开发环境搭建(参考流程) 2013-08-08 01:09:06 分类: LINUX 原文地址:django开发环境搭建(参考流程) 作者:bailiangcn 对于一个初学者,在实际的开 ...
随机推荐
- python高阶函数—filter
python内置了一个filter函数,用于过滤序列.和map函数类似,filter()函数也接受一个函数和一个序列.只不过filter函数中是把函数依次作用于序列中的每一个元素,如果是True则保留 ...
- Nginx代理前端代码
Nginx 安装配置 Nginx("engine x")是一款是由俄罗斯的程序设计师Igor Sysoev所开发高性能的 Web和 反向代理 服务器,也是一个 IMAP/POP3/ ...
- 11.2 Data Guard Physical Standby Switchover Best Practices using SQL*Plus (Doc ID 1304939.1)
11.2 Data Guard Physical Standby Switchover Best Practices using SQL*Plus (Doc ID 1304939.1) APPLIES ...
- leetcode动态规划--基础题
跳跃游戏 给定一个非负整数数组,你最初位于数组的第一个位置. 数组中的每个元素代表你在该位置可以跳跃的最大长度. 判断你是否能够到达最后一个位置. 思路 根据题目意思,最大跳跃距离,说明可以跳0--n ...
- 07-Node.js学习笔记-路由
路由 http://localhost:3000/index http://localhost:3000/login //路由是指客户端请求地址与服务器端程序代码的对应关系.简单的说,就是请求什么响应 ...
- IT兄弟连 HTML5教程 HTML5表单 HTML表单设计1
表单是PHP程序中最常使用的收集站点访问者信息的数据输入界面.通过表单浏览器获取用户的输入数据,并传送给Web服务器的脚本程序中,以各种不同的方式进行处理.在表单中提供了多种输入方式,包括文本输入域. ...
- Windows下使用virtualenv创建虚拟环境
操作系统 : windowns10_x64Python版本:3.6.8virtualenv版本:16.7.7virtualenvwrapper版本:1.2.5 方式一:直接使用virtualenv 1 ...
- C 语言输出不同颜色字体
C 语言输出不同颜色字体 \033是8进制,它就是unix下终端转义符ESC(16进制1A,10进制27) ESC[xm 是unix下改变终端输出颜色的命令 所以,如果是红色,则我们定义为\033[0 ...
- Windows10 搭建Kafka集群
下载Kafka 1.下载Kafka:http://mirror.bit.edu.cn/apache/kafka/2.3.0/kafka_2.12-2.3.0.tgz 2.解压后复制Kafka文件夹,分 ...
- 松软科技web课堂:SQLServer之SUM() 函数
SUM() 函数 SUM 函数返回数值列的总数(总额). SQL SUM() 语法 SELECT SUM(column_name) FROM table_name SQL SUM() 实例 我们拥有下 ...