第一步:进行环境的搭建(用到的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开发网上教育平台(参考了慕课网的教学视频)的更多相关文章

  1. Django:学习笔记(1)——开发环境配置

    Django:学习笔记(1)——开发环境配置 Django的安装与配置 安装Django 首先,我们可以执行python -m django --version命令,查看是否已安装django. 如果 ...

  2. django+xadmin在线教育平台(五)

    3-3 django orm介绍与model设计 上节教程完成后代码(来学习本节前置条件): 对应commit: 留言板前端页面展示.本次内容截止教程3-2结束. 可能现在你还在通过手写sql语句来操 ...

  3. django+xadmin在线教育平台(四)

    3-2 配置表单页面 必要的该说的,该了解的 前置条件: 你已经学习了前面教程.将项目的文件夹目录结构,setting配置等修改完毕与我保持一致. 本节通过Django快速的配置一个留言板页面来学习 ...

  4. django开发微信公众平台遇到的问题记录

    在pythonanywhere.com上使用django开发微信公众平台应用,结果用户发送的信息,微信服务器一次也没有成功转发到pythonanywhere上来,但是用接口测试工具调试却发现是正常的, ...

  5. VSTO学习笔记(三) 开发Office 2010 64位COM加载项

    原文:VSTO学习笔记(三) 开发Office 2010 64位COM加载项 一.加载项简介 Office提供了多种用于扩展Office应用程序功能的模式,常见的有: 1.Office 自动化程序(A ...

  6. Aurora学习笔记连载一:仿真平台搭建

    由于公司项目需要,需要学习Aurora协议,才有了这样的连载学习笔记,也算是对自己学习的一份记录吧. 对于Aurora是什么,大家自行百度. 当然,Kevin也在此先提醒大家,本套学习笔记不是你想学就 ...

  7. python学习笔记--Django入门四 管理站点--二

    接上一节  python学习笔记--Django入门四 管理站点 设置字段可选 编辑Book模块在email字段上加上blank=True,指定email字段为可选,代码如下: class Autho ...

  8. Android:日常学习笔记(8)———开发微信聊天界面

    Android:日常学习笔记(8)———开发微信聊天界面 只做Nine-Patch图片 Nine-Patch是一种被特殊处理过的PNG图片,能够指定哪些区域可以被拉升,哪些区域不可以.

  9. django开发环境搭建(参考流程)

    django开发环境搭建(参考流程) 2013-08-08 01:09:06 分类: LINUX 原文地址:django开发环境搭建(参考流程) 作者:bailiangcn 对于一个初学者,在实际的开 ...

随机推荐

  1. Splash 学习笔记

    一.介绍 Splash 跟之前我们介绍的 Selenium ( 参考 Selenium 与自动化测试 -- <Selenium 2 自动化测试实战>读书笔记) 很类似,都可以理解成一个浏览 ...

  2. 利用WPF生成Q币充值二维码——扫码登录篇

    一.前言 虽然腾讯官方不支持使用二维码充值Q币,但对于喜欢钻研的人来说这不是问题,本文利用WPF技术讲解从扫码登录到生成Q币充值二维码的一整套解决方案. 因为充值Q币需要先用QQ号登录官网.所以我们首 ...

  3. IPFS学习-分布式哈希表DHT

    Distributed Hash Tables(DHT) 分布式哈希表是一个分布式的键值对存储结构.在IPFS网络中,每一个节点都维护一个DHT的子集.当节点接受到一个请求.该节点要么直接回复,要么通 ...

  4. tomcat的jsp页面超过65535,导致500报错

    错误信息 org.apache.jasper.JasperException: Unable to compile class for JSP: An error occurred at line: ...

  5. C# 调用OpenCVSharp报错“尝试读取或写入受保护的内存。这通常指示其他内存已损坏”

    一.描述问题 当托管代码调用非托管代码的时候,经常会出现如下报错:“尝试读取或写入受保护的内存.这通常指示其他内存已损坏”. 二.原因分析 由于非托管代码的内存指针的回收是由非托管代码自身手动完成的, ...

  6. Class文件结构-常量池

    常量池里存放:1.字面量(Literal) • 文本字符串 • 声明为final的常量值(final的8种基本类型) • 非final的基本类型也可能进(doublefloatlong)2.符号引用( ...

  7. 前端面试题套路--终极版(Vue、JavaScript)

    前言 面试题是永远都准备不完的!!!!! 前端常见的一些问题 1.前端性能优化手段? 1. 尽可能使用雪碧图 2. 使用字体图标代替图片 3. 对HTML,css,js 文件进行压缩 4. 模块按需加 ...

  8. JavaScript高阶函数(Heigher-order function)

    概念 <javascript设计模式和开发实践>中定义 函数既可作为参数被传递,也可以作为返回值输出 满足以下条件: 接受一个或多个函数作为输入 输出一个函数 高阶函数一般是那些函数型包含 ...

  9. Redis Python(二)

    Infi-chu: http://www.cnblogs.com/Infi-chu/ 一.NoSQL(Not only SQL)1.泛指非关系数据库2.不支持SQL语法3.存储结构与传统的关系型数据库 ...

  10. 打包vue文件,上传到服务器

    主要步骤: 1. npm run build生成dist文件夹 2. 将dist文件夹上传到服务器上 3. 服务器上配置nginx,访问路径指向dist文件夹下的index.html,这样当访问ngi ...