一需求:

具备的功能:

1. 业务逻辑分析

1.1 要实现的功能
1.1.1 用户可用功能
1.1.2 后台管理功能
1.2 要创建的app
1.2.1 course(课程)
1.2.2 user(用户)

2. Model层开发

2.1 创建Django项目
2.2 分析表结构和创建
2.2.1 用户表:User
2.2.2 课程表:Course
2.2.3 课程种类表:Category
2.2.4 表结构的创建
2.3 表结构的迁移
2.4 创建存储网页资源的文件夹

3. Admin后台管理

3.1 创建超级管理员账户
3.2 登录后台管理系统
3.3 注册创建的模型类
3.4 配置后台管理页面的显示内容
3.5 配置app在后台显示的名称
3.6 配置模型类表的显示中⽂名称
3.7 定义某些字段可以为空

4. 路由与视图

4.1 在创建的app中创建urls.py文件
4.2 在总路由文件urls.py中载件两个app的urls.py文件
4.3 在course的urls.py文件中配置路由映射
4.4 在course的views.py视图文件中创建对应的视图函数
4.5 在user的urls.py文件中配置路由映射
4.6 在user的views.py视图文件中创建对应的视图函数

5. 商品首页后端数据渲染

5.1 创建静态网页资源
5.1.1 在static文件夹下
5.1.2 在templates文件夹中
5.1.3 在settings.py中配置静态资
5.2 抽离html模板的各个模块
5.3 根据各个html页面需求,引⽤抽离的模块并做相应的修改

6. 用户个人管理页面

6.1 配置用户注册页面
6.2 创建中间件
6.3 配置用户登录界面
6.4 配置用户注销界面
6.5 配置用户主页base.html

7. 购物车功能完善

7.1 商品详细页
7.2 添加购物车与展示
7.3 购买课程与已购买课程

8. 视频传输权限与协议
9. 网站安全性优化

后端管理功能
1.1课程平台首页展示

1.2登录注册功能


1.3课程详情页

1.4加入购物车功能,立即购买功能

1.5个人详情页


1.6观看功能

2.1后端管理功能

2.2用户表

2.3课程表

二.代码实现

1. 业务逻辑分析
1.1 要实现的功能

1.1.1 用户可用功能
用户注册
用户登录、修改客户资料
用户注销
用户购买课程以及查看已购买课程
用户把课程加入购物车以及查看购物车
1.1.2 后台管理功能
用户表——管理用户(增删改用户信息及用户余额等)
上线课程——管理课程(增加新课程、上传课程相关文件和信息)
课程种类——管理课程类型(新增课程类型)

1.2 要创建的app

1.2.1 course(课程)
商城主页
页面展示所有课程的名称和价格,课程按课程类型排列
课程详细页
展示该课程的详细信息:名称、创建日期、价格,根据用户情况提供加入购物车、购买课程、直接观看
视频的接口
视频播放页
调视频流接口,实现安全播放视频功能
视频流接口
用安全的方式,把视频以视频流的形式输出到浏览器客户端
1.2.2 user(用户)
用户主页
通过get方法,展示用户信息:账号、户名、余额、性别等
通过post方法,修改接口
已购买课程页面
展示用户已购买的所有课程,可以直接进入观看
购物车页面
展示用户购物⻋内的所有课程
登录、注册、注销接口
根据不同场景提供不同的接口,并确保在未登陆情况下不可以访问需要登陆后或购买课程后才可以访问
的页面,互相之间不能造成影响
课程购买接口
加入购物车接口

2. Model层开发
2.1 创建Django项目

直接在PyCharm中创建Django项目,同时创建一个user的app
打开settings.py,配置数据库

DATABASES = {'default': {'ENGINE': 'django.db.backends.mysql','HOST': 'localhost','PORT': '3306','NAME': 'csdn_course', # 数据库名称尽量跟项目名称一致'USER': 'root','PASSWORD': '123456'}
}

在MySQL中创建这个相应的数据库
修改settings.py中的语言和时区设置

LANGUAGE_CODE = 'zh-hans' # 中国
TIME_ZONE = 'Asia/Shanghai' # 东八区时区
2.2 分析表结构和创建

2.2.1 用户表:User

2.2.2 课程表:Course

2.2.3 课程种类表:Category

2.2.4 表结构的创建

from django.db import models
#用户表, 可以留空的字段传blank=True参数, 表单提交时可为空
class User(models.Model):class Meta():
#创建Meta类, 配置verbose_name, 让页面显示字段的中文名称verbose_name = verbose_name_plural = '用户表'
account = models.CharField(max_length=16, unique=True, verbose_name='账 号')
#账号唯一, 传入verbose_name参数使其显示中文名称
password = models.CharField(max_length=16, verbose_name='密码')
username = models.CharField(max_length=16, verbose_name='用户名',blank=True)
money = models.DecimalField(max_digits=12, decimal_places=2,default=0, verbose_name='余额')
#总位数12,小数位2
#0:男,1:女,默认0,传入choices=((0, '男'), (1, '女'))参数, 在后台提供下拉选项,choices里面的元素为元组
gender = models.PositiveSmallIntegerField(default=0, verbose_name='性 别', choices=((0, '男'), (1, '女')))
tel = models.CharField(max_length=11, default='',verbose_name='手机号', blank=True)def __str__(self):return self.account
# 定义__str__方法, 返回字段account, 在页面中直接显示该字段的名称

课程表

from django.db import models
import datetime
from user.models import User
import os# 定义存储课程视频路径的方法
def save_file(instance, filename):# 视频存储在根目录下的video文件夹内return os.path.join('video', filename)# 定义存储课程图片路径的方法
def save_img(instance, filename):# 图片存储在根目录下static文件夹下的img文件夹内return os.path.join('static', 'img', filename)# 课程种类表, 传入verbose_name参数让页面显示中文名称
class Category(models.Model):class Meta():  # 创建一个Meta类, 配置verbose_name, 让页面显示字段的中文名称verbose_name = verbose_name_plural = '课程种类表'name = models.CharField(max_length=50, unique=True, verbose_name='课程种类')def __str__(self):  # 定义__str__方法, 返回字段name, 在页面中直接显示字段的名称return self.name# 课程表, 传入verbose_name参数让页面显示中文名称, blank=True允许表单传入数据为空
class Course(models.Model):# 创建一个存储收费与否的元组, 传入status作为参数, 提供显示中文名称的下拉菜单STATUS_CHOICES = ((0, '收费'),(1, '免费'))class Meta():  # 创建一个Meta类, 配置verbose_name, 让页面显示字段的中文名称verbose_name = verbose_name_plural = '课程表'courseName = models.CharField(max_length=40, verbose_name='课程名称')fileName = models.FileField(upload_to=save_file, verbose_name='文件名称')   # upload_to参数调用存储视频路径方法拿到视频存储路径imgname = models.ImageField(upload_to=save_img, verbose_name='课程图片')    # upload_to参数调用存储图片路径方法拿到图片存储路径# 设置课程种类的外键连接, 一对多的关系, 设置反向查找的related_name, 便于反向查找pCategory = models.ForeignKey(to=Category, related_name='courses_set', on_delete=models.CASCADE,verbose_name='课程类别')price = models.DecimalField(max_digits=7, decimal_places=2, default=0, verbose_name='售价', blank=True)summary = models.CharField(max_length=1000, default='', verbose_name='课程介绍', blank=True)status = models.PositiveSmallIntegerField(default=0, verbose_name='状态', blank=True,choices=STATUS_CHOICES)  # 0:收费 1:免费,默认0createDatetime = models.DateTimeField(default=datetime.datetime.now(), verbose_name='创建时间', blank=True)# 定义已购买课程用户跟课程的多对多关系, 设置反向查找的related_nameuserBuyer = models.ManyToManyField(to=User, related_name='userBuyer_set', verbose_name='购买用户', blank=True)# 定义加入购物车的用户跟课程的多对多关系, 设置反向查找的related_nameuserShoppingcart = models.ManyToManyField(to=User, related_name='userShoppingcart_set', verbose_name='加入购物车的用户',blank=True)

课程种类表

# 课程种类表, 传入verbose_name参数让页面显示中文名称
class Category(models.Model):#创建一个Meta类, 配置verbose_name, 让页面显示字段的中文名称class Meta(): verbose_name = verbose_name_plural = '课程种类表'name = models.CharField(max_length=50, unique=True, verbose_name='课程种类')def __str__(self): # 定义__str__方法 返回字段name, 在页面中直接显示字段的名称return self.name

2.3 表结构的迁移
在终端中生成迁移文件

python3 manage.py makemigrations

在终端中行迁移文件

python3 manage.py migrate

2.4 创建存储网页资源的文件夹
在根录中创建stati文件夹,在static文件夹中创建img文件夹用来存储上传的图片文件
在根目录中创建video文件夹,用来存储上传的视频文件
3. Admin后台管理
3.1 创建超级管理员账户
django会自动生成admin后台管理页面,可以通过管理员账户直接登录进入后台管理
在终端中执行以下代码创建超级管理员账户

python3 manage.py createsuperuser

输入用户名、邮箱、密码即可创建
3.2 登录后台管理系统
通过主页/admin进入后台管理登录页面,输入账号和密码登录,即可进入后台管理界面
3.3 注册创建的模型类
在每个app文件夹下的admin.py文件中,注册创建的模型类
course app

from django.contrib import admin
from .models import Course, Category
# 导入所有的模型类
# 注册这个app内创建的模型类
@admin.register(Category) # 传⼊模型类名作为参数
class CategoryAdmin(admin.ModelAdmin): #创建这个类名的Admin类, 继承admin.ModelAdmin类list_display = ['name'] # 设置该模型类中要显示的字段search_fields = ['name'] #设置可以通过哪个字段进行查找
@admin.register(Course)
class CourseAdmin(admin.ModelAdmin):filter_horizontal = ['userBuyer', 'userShoppingcart'] #设置侧边栏显示这两个字段, 界面对用户比较友好
list_display = ['id', 'courseName', 'pCategory', 'price', 'summary','status', 'createDatetime']
#设置该模型类中要显示的字段
list_filter = ['status', 'createDatetime']
# 设置过滤器, 选择可以通过哪个字段来过滤显示
search_fields = ['courseName', 'price']
#设置可以通过哪个字段进⾏查找搜索

user app

from django.contrib import admin
from .models import User
# 导入所有的模型类
# 注册这个app内创建的模型类
@admin.register(User) # 传入模型类名作为参数
class UserAdmin(admin.ModelAdmin):
# 创建这个类名的Admin类, 继承admin.ModelAdmin类list_display = ['id', 'account', 'username', 'money', 'gender', 'tel']
# 设置要显示的字段名称list_filter = ['gender']
# 设置可以通过哪个字段进⾏筛选search_fields = ['account', 'username']
# 设置可以通过哪个字段进⾏搜索查找

3.4 配置后台管理用户的显示内容
在任意一个admin.py中,加入以下代码

admin.site.site_header = 'CSDN微课后台管理' #页面中显示标题
admin.site.index_title = '后台系统' # 标签页中显示前缀
admin.site.site_title = '管理' # 标签中显示后缀

3.5 配置app在后台显示的名称
在每个app文件夹下的apps.py文件中,创建app在后台的显示名称

  • course
from django.apps import AppConfig
class CourseConfig(AppConfig):name = course#配置verbose_name  让页面显示中文verbose_name = '课程管理'
  • user
from django.apps import AppConfig
class UserConfig(AppConfig):name = 'user'# 配置verbose_name, 让页面可以显示字段的中文名称verbose_name = ''用户管理'

3.6 配置模型类表的显示中⽂名称
在每个app的models.py文件中,在每个类之中加入以下代码

  • course
# 课程种类表
class Category(models.Model):class Meta():verbose_name = verbose_name_plural = '课程种类表'
  • category
# 课程表:
class Course(models.Model):class Meta():verbose_name = verbose_name_plural = '课程表'
  • user
#用户表
class User(models.Model):class Meta():verbose_name = verbose_name_plural = '用户表'

3.7 定义某些字段可以为空
在模型类中该字段的传入参数中添加blank=True即可
4. 路由与视图
4.1 在创建的app中创建urls.py文件
4.2 在总路由文件urls.py中载入两个app的urls.py文件

from django.contrib import admin
from django.urls import path, include
urlpatterns = [path('admin/', admin.site.urls),path('', include('course.urls')), # 载人course的urls文件path('user/', include('user.urls')), # 载入app的urls文件
]

4.3 在course的urls.py⽂件中配置路由映射

from django.urls import path, re_path
from . import views
urlpatterns = [path('', views.index_handler, name='course_index'), # 定义商城主页的路由re_path('course/(.+)', views.course_handler, name='course_course'),# 通过正则匹配课程的详细页面, 传入course_id作为参数re_path('video/(.+)', views.video_handler, name='course_video'), # 匹配视频播放页面, 传入course_id作为参数获取视频re_path('videoStream/(.+)', views.videoStream_handler,name='course_videoStream'), # 匹配视频流文件, 根据course_id获取
]

4.4 在course的views.py视图文件中创建对应的视图函数

# 对应视图函数的设置见后面具体章节的配置

4.5 在user的urls.py文件中配置路由映射

from django.urls import path, re_path
from . import views
urlpatterns = [path('', views.index_handler, name='user_index'), # 定义用户主页的路由path('course', views.course_handler, name='user_course'), # 定义用户已购买课程页面的路由path('shoppingCart', views.shoppingCart_handler,name='user_shoppingCart'), # 定义用户购物车页面的路由path('login', views.login_handler, name='user_login'), # 定义登录接的路由path('register', views.register_handler, name='user_register'),# 定义注册接入的路由path('logout', views.logout_handler, name='user_logout'),# 定义注销接入的路由re_path('purchase/(.+)', views.purchase_handler, name='user_purchase'), # 定义购买课程接入的路由                                                                                       re_path('addShoppingCart/(.+)', views.addShoppingCart_handler,name='user_addShoppingCart') # 定义加入购物车接入的路由]

4.6 在user的views.py视图文件中创建对应的视图函数

# 对应视图函数的设置见后面具体章节的配置
  1. 商品页面后端数据渲染
    5.1 创建静态文件资源
    5.1.1 在static文件夹下
    创建CSS文件夹,放在css文件
    创建js文件夹,放在js文件
    5.1.2 在templates文件件夹中
    创建base.html文件(直接提供的模板),作为所有视图页面的引用模板
    创建各个视图函数对应的渲染页面

5.1.3 在settings.py中配置静态资源

#在settings.py文件的最后添加以下代码
STATIC_URL = '/static/'
STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static')]

5.2 抽离html模板的各个模块
5.3 根据各个html页面需求,引入抽离的模块并做相应的修改
6. 用户个人页面管理
6.1 配置用户注册页面

视图函数代码

  • 用户注册视图函数
# 用户注册视图函数
def register_handler(request):if request.method != 'POST':  # 判断如果请求方式不是post, 返回403错误return HttpResponse(status=403)context = request.context  # 通过request先处理context内容account = request.POST.get('account')  # 获取账号和密码password = request.POST.get('password')try:user_exists = User.objects.filter(account=account).exists()  # 判断账号是否已经存在if not user_exists:user = User(account=account, password=password)  # 如果不存在, 则存储用户注册的账号和密码user.save()request.session['session_user'] = {'id': user.id, 'account': user.account}  # 并保存账户登录的sessionelse:context['register_message'] = '账号已存在'  # 如果已存在账号, 返回一个提示信息except:context['register_message'] = '服务器异常'   # 如果执行到except代码块, 提示服务器异常finally:return course_views.index_handler(request)  # 最终返回所有课程的商城主页
  • base.html页面代码
<!-- 注册 -->
<div id="register"{% if not register_message %}{# 如果出现提示异常的信息, 注册的标签取消隐藏 #}hidden="hidden">{% endif %}<h2 class="form_p">注册</h2> <p id="register_message">{{ register_message }}<!--信息有误--></p>
<form action="{% url 'user_register' %}" method="post"  id="register_form">{% csrf_token %}<input id="register_account"  type="text"  name="account"placeholder="账号(数字、英⽂、下换线,8-16位)"><br/><input id="register_password" type="password" name="password"placeholder="密码(数字、英⽂、下换线,6-16位)"><br/><!--<input type="password" name="repassword" placeholder="确认密码"><br/>--><input id="register_submit" type="submit" value="注册">
</form>
</div>

6.2 创建中间件在根目录新建个middleware.py文件,插入以下代码

from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import reverse
from course import views as course_viewsclass MyMiddleware(MiddlewareMixin):def __init__(self,get_response=None):super().__init__(get_response)# 初始化中间件print('init_mymiddleware')def process_request(self,request):# request.context={}# session_user=None# if 'session_user' in request.session.keys():#     request.context['session_user']=request.session['session_user']# if not session_user:#     if request.path.startswith('/video') or request.path.startswith('/user'):#         if request.path not in [reverse('user_login'),reverse('user_rigister')]:#             request.context['login_message']='请先登录'#         return course_views.index_handdler(request)request.context = dict(session_user = request.session['session_user'] if'session_user' in request.session.keys() else None)if (not request.context['session_user'])\and (request.path.startswith('/video') or request.path.startswith('/user')) \and request.path not in [reverse('user_login'),reverse('user_register')]:request.context['login_message'] = '请先登录'return course_views.index_handler(request)def process_response(self,request,response):# 必须return responseprint('process_response')return response

6.3 配置用户登录文件

  • 视图函数
# 用户登录视图函数
def login_handler(request):if request.method != 'POST':# 如果请求方式不是post, 返回403禁止访问return HttpResponse(status=403)context = request.contextaccount = request.POST.get('account')password = request.POST.get('password')user_s = User.objects.filter(account=account, password=password) #查找用户对象中是否存在匹配的账户和密码if user_s:user = user_s[0] # 如果存在, 则获取第⼀个匹配的⽤户request.session['session_user'] = {'id': user.id, 'account':user.account} # 创建session_userreturn redirect(reverse('course_index')) # 登录成功后重定向到商城主页# context['session_user'] = {'id': user.id, 'account':user.account}else:context['login_message'] = '账号或密码错误!' # 如果不存在对应的账户和密码, 提示错误信息return course_views.index_handler(request) # 返回页面视图

base.html

<div id="login"{% if not login_message %}hidden="hidden"{% endif %}><h2 class="form_p">登录</h2><p id="login_message"><!--信息有误-->{{login_message}}</p><form action="{% url 'user_login' %}" method="post" id="login_form">{% csrf_token %}<input id="login_account" type="text" name="account" placeholder="账号"><br><input id="login_password" type="password" name="password" placeholder="密码"><br><input id="login_submit" type="submit" value="登录"></form>
</div>

6.4 配置用户注销页面

  • 视图函数
# 用户注销登录视图函数
def logout_handler(request):# 如果用户点击注销, 把用户的session设置为Nonerequest.session['session_user'] = None# 页面重定向到商城主页return redirect(reverse('course_index'))

6.5 配置用户主页user.html

  • 视图函数
def index_handler(request):context = request.context # 获取中间件处理的contextsession_user = request.session['session_user'] # 获取登录的用户user = User.objects.get(id=session_user.get('id')) # 获取用户信息context['user'] = userif request.method == 'GET': # 如果是get请求, 直接返回用户主页详情return render(request, 'user.html', context)else: # 如果是post请求, 要获取账户名/性别/电话, 并保存用户信息user.username = request.POST.get('username')user.gender = request.POST.get('gender')user.tel = request.POST.get('tel')user.save()return redirect(reverse('user_index')) # 重定向到用户主页

user.html

{% extends 'base.html' %}
{% block title %}
{% endblock %}
{% block article %}<article><section class="main_section"><hr><section id="user_manage"><nav><p><a href="{% url 'user_index' %}">个人资料</a></p><p><a href="{% url 'user_course' %}">我的课程</a></p><p><a href="{% url 'user_shoppingCart' %}">购物车</a></p></nav><section class="user_info"><div class="user_info_wrapper"><ul><li><label>账&#12288;号:</label><span>{{ user.account }}</span></li><li><label>余&#12288;额:</label><span>{{ user.money }}</span></li></ul><form action="{% url 'user_index' %}" method="post">{% csrf_token %}<ul><li><label>用户名:</label><input type="text" name="username" value="{{ user.username }}"></li><li><label>性&#12288;别:</label>{% if not user.gender %}<input type="radio" name="gender" value="0" checked="checked">男<input type="radio" name="gender" value="1">女{% else %}<input type="radio" name="gender" value="0">男<input type="radio" name="gender" value="1" checked="checked">女{% endif %}</li><li><label>手机号:</label><input type="text" name="tel" value="{{ user.tel }}"></li><li><input type="submit" value="修改"><input type="reset" value="重置">

购物车功能完善
7.1 商品详细页

  • 视图函数
# 定义课程商品详细页视图函数
def course_handler(request, course_id):context = request.context                       # 通过request先处理context再传入函数中try:                                            # 如果课程存在, 则返回课程页面course = Course.objects.get(id=course_id)session_user = request.sessi    on.get('session_user', None)if session_user:# 用户登录以后, 通过用户id查询该用户是否已经购买该课程, 判断是否允许其观看对应课程的视频context['view_permission'] = User.objects.filter(id=session_user.get('id'), userBuyer_set__id=course.id).exists()context['course'] = coursereturn render(request, 'course.html', context)except:                                         # 如果课程不存在, 返回404页面return HttpResponse(status=404)

course.html

{% extends 'base.html' %}
{% block title %}{{ course.pCategory.name }}
{% endblock %}
{% block article %}<article><section class="main_section"><section class="course_detail"><img src="/{{ course.imgname }}" alt=""><div class="course_detail_div"><h1>{{ course.courseName }} </h1><p>课程种类:{{ course.pCategory.name }}</p><p>发布时间:{{ course.createDatetime| date:'Y-m-d' }}</p><p>价格:<span class="price">{{ course.price }}</span></p><p>{% if not view_permission %}<a href="{% url 'user_addShoppingCart' course.id %}">加入购物车</a><a href="{% url 'user_purchase' course.id %}">立即购买</a>{% else %}<a href="{% url 'course_video' course.id %}">立即观看</a>{% endif %}</p></div></section><section class="course_summary"><h2>[课程介绍]</h2><p class="summary_p">{{ course.summary }}</p></section></section></article>
{% endblock %}

7.2 添加购物车与展示

  • 视图函数
def addShoppingCart_handler(request, course_id):context = request.context       # 获取request传递过来的contexttry:course = Course.objects.get(id=course_id)       # 通过course_id获取对应的课程session_user = request.session['session_user']  # 获取登录的用户user = User.objects.get(id=session_user.get('id'))  # 根据用户的id获取用户对象user.userShoppingcart_set.add(course)               # 把课程添加进用户的购物车中user.save()                                         # 保存用户对象context['message'] = '添加购物车成功'except:context['message'] = '添加购物车失败'return render(request, 'user_message.html', context)    # 返回用户信息结果视图
# 用户购物车视图函数
def shoppingCart_handler(request):context = request.context       # 获取request传入的contextsession_user = request.session['session_user']      # 获取登录的用户course_s = User.objects.get(id=session_user.get('id')).userShoppingcart_set.all()   # 获取用户已经加入购物车的所有课程context['course_s'] = course_s      # 封装到context里面return render(request, 'user_shoppingcart.html', context)   # 传入到返回的购物车页面

user_message.html

{% extends 'base.html' %}
{% block title %}
{% endblock %}
{% block article %}<article><section class="main_section"><hr><section id="user_manage"><nav>{#  根据路由映射, 找到对应的视图  #}<p><a href="{% url 'user_index' %}">个人资料</a></p><p><a href="{% url 'user_course' %}">我的课程</a></p><p><a href="{% url 'user_shoppingCart' %}">购物车</a></p></nav><section class="user_info"><div class="user_info_wrapper"><h1>{{ message }}</h1></div></section></section></section></article>
{% endblock %}

user_shoppingcart.html

{% extends 'base.html' %}
{% block title %}
{% endblock %}
{% block article %}<article><section class="main_section"><hr><section id="user_manage"><nav><p><a href="{% url 'user_index' %}">个人资料</a></p><p><a href="{% url 'user_course' %}">我的课程</a></p><p><a href="{% url 'user_shoppingCart' %}">购物车</a></p></nav><section class="user_info"><div class="user_info_wrapper"><table id="user_shopping_cart" cellpadding="0" cellspacing="0"><tr id="user_shopping_cart_tr_first"><th width="250px">课程名称</th><th width="100px">价格</th><th width="200px">上线时间</th><th width="100px">操作</th></tr>{% for course in course_s %}<tr class="user_info_shopping_tr"><td>{{course.courseName}}</td><td style="color:red;">{{ course.price }}</td><td>{{ course.createDatetime|date:'Y-m-d' }}</td><td><a href="{% url 'user_purchase' course.id %}">立即购买</a></td></tr>{% endfor %}</table></div></section></section></section></article>
{% endblock %}

7.3 购买课程与已购买课程

  • 用户购买课程的视图函数
# 用户购买课程视图函数
def purchase_handler(request, course_id):context = request.contexttry:course = Course.objects.get(id=course_id)       # 通过course_id获取到课程对象session_user = request.session['session_user']  # 获取登录客户user = User.objects.get(id=session_user.get('id'))if user.money >= course.price:                  # 如果用户余额大于课程价格, 直接购买, 减少相应的价格user.userBuyer_set.add(course)user.money -= course.priceuser.save()                                 # 保存用户购买信息, 并提示成功context['message'] = '购买成功!'else:context['message'] = '余额不足!'             # 否则提示余额不足except:context['message'] = '购买失败!'finally:return render(request, 'user_message.html', context)    # 返回用户信息页面, 传入提示信息
  • 用户已购买课程视图函数
# 用户已购买课程视图函数
def course_handler(request):context = request.contextsession_user = request.session['session_user']      # 获取登录用户course_s = User.objects.get(id=session_user.get('id')).userBuyer_set.all()  # 通过user_id获取已购买的课程context['course_s'] = course_sreturn render(request, 'user_course.html', context)     # 返回用户已购买课程页面

8. 视频传输权限与协议

8.1 视频播放页面视图函数

# 视频播放页面视图函数
def video_handler(request, course_id):context = request.contexttry:course = Course.objects.get(id=course_id)session_user = request.session['session_user']  # 获取登录用户# 通过course_id判断该用户是否已经购买该课程boolean_buyed = User.objects.filter(id=session_user.get('id'), userBuyer_set__id=course_id).exists()if boolean_buyed:context['course'] = coursereturn render(request, 'video.html', context)   # 如果已经购买课程, 直接返回到视频播放页面else:return redirect(reverse('course_course', args=(course_id, )))   # 否则返回到课程详细页except:return HttpResponse(status=404)     # 如果找不到课程, 返回404页面

8.2 视频流视图函数(更安全,不需要直接把整个视频件传输出去)

# 视频流播放视图函数
def videoStream_handler(request, course_id):# 定义读取视频流的方法def read_video(path):   # 传入视频路径with open(path, 'rb') as f: # 以二进制读取方式打开视频文件while True:data = f.read(1024*10)  # 获取视频文件内容, 每次读取?if data:yield data          # 遍历获取视频内容, 生成视频内容, 直到视频结束else:breakcontext = request.contexttry:course = Course.objects.get(id=course_id)       # 获取课程session_user = request.session['session_user']  # 获取登录客户# 判断用户是否已购买该课程boolean_buyed = User.objects.filter(id=session_user.get('id'), userBuyer_set__id=course_id).exists()if boolean_buyed:   # 如果已购买, 通过之前读取视频流的方法, 返回视频流播放界面context['course'] = course# 实例化response对象, 调用读取视频流的方法response = StreamingHttpResponse(read_video(course.fileName.__str__()), status=206)bytes_max = 1024 * 1024 * 2     # 限定2M大小# 设置视频流对象的参数, 固定用法?response['Content-Range'] = 'bytes 0-102400/%s' % (bytes_max, os.path.getsize(course.fileName.__str__()))return responseelse:return redirect(reverse('course_course', args=(course_id, )))   # 否则返回到课程详细页except:return HttpResponse(status=404)     # 如果找不到课程, 返回404页面

9.网站安全性优化

  • 通过中间件设置,对特定url地址的访问作出限制,给出相应提示
from django.utils.deprecation import MiddlewareMixin
from course import views as course_views
from django.shortcuts import reverse
class MyMiddleware(MiddlewareMixin):def __init__(self, get_response=None):super().__init__(get_response)# 初始化中间件print('Initiating MyMiddleWare...')def process_request(self, request):# request.context = {}# # 如果没有session_user, 直接返回None# session_user = None# # 如果session_user已经存在, 则把session_user封装到context中# if 'session_user' in request.session.keys():#     session_user = request.context['session_user'] = request.session['session_user']# # 如果没有session_user, 用户想访问视频页面或登录页面的时候, 提示用户先登录# if not session_user:#     if request.path.startswith('/video') or request.path.startswith('/user'):#         # 通过判断账号和密码是否已经存在, 把登录接口让出来, 避免所有的登录和注册都被阻拦#         if request.path not in [reverse('user_login'), reverse('user_register')]:#             request.context['login_message'] = '请先登录!'#             return course_views.index_handler(request)# 通过dict()函数简化第13行到16行的代码request.context = dict(session_user=request.session['session_user'] if 'session_user' in request.session.keys() else None)# 通过并列条件判断, 合并第17行到19行的条件嵌套if (not request.context['session_user']) \and (request.path.startswith('/video') or request.path.startswith('/user')) \and (request.path not in [reverse('user_login'), reverse('user_register')]):request.context['login_message'] = '请先登录!'return course_views.index_handler(request)def process_response(self, request, response):print('Processing Response...')# 必须return response, 否则会报错return response

django实战项目课程平台搭建相关推荐

  1. Django 快速入门课程「搭建个人博客」

    文章目录 1. 初探 Django 1. Why Django? 2. 新建 Python 虚拟环境 3. 安装 Django 并新建项目 4. 初始化生成文件用途 5. 检测 Django 项目是否 ...

  2. Django实战项目--爱鲜蜂day1

    实战第一天 创建虚拟环境 使用cmd进入到储存项目文件 virtualenv --no-site-packages testenv# 创建文件testenv 在虚拟环境中安装pymysql和djang ...

  3. 缺少项目经验 找工作处处碰壁?这 240 个实战项目请打包带走!

    全部面试找工作时,最常被问到的问题就是:有什么项目经验? 对于毕业生来说,我们刚走出校园,还没有工作和项目经验,只能拿学校里练习做的 "小游戏" 或者 "命令行程序&qu ...

  4. python飞机大战任务报告_Python飞机大战实战项目案例

    都说实践是检验知识掌握程度的最好测试.随着Python学习者的增长,越来越多的零基础入门课程让人眼花缭乱.虽然说基础理论的学习十分重要,但是如果仅仅只学习理论知识,也是远远不够的.飞机大战的项目实战可 ...

  5. python实战一个完整的项目-年终课程盘点|16 个 Python 综合实战项目合集

    今天,就来给大家盘点一下,2019 年实验楼的 Pyhton 项目里,最值得一做的几个项目. 警告: 本来只想推荐几个课程的,但 Python 的好项目实在是太多了!无法割舍,最后决定推荐 16 个. ...

  6. 【.NET Core项目实战-统一认证平台】第三章 网关篇-数据库存储配置(1)

    [.NET Core项目实战-统一认证平台]第三章 网关篇-数据库存储配置(1) 原文:[.NET Core项目实战-统一认证平台]第三章 网关篇-数据库存储配置(1) [.NET Core项目实战- ...

  7. 视频教程-Angular+Django前后端分离实战项目开发教程-AngularJS

    Angular+Django前后端分离实战项目开发教程 胜蓝博创(韬略课堂)创始人,IT培训讲师,先后在蓝港在线,热酷,乐元素等大型游戏公司任职,参与过多款大型网游.手游的设计和开发,精通页游.手游前 ...

  8. RocketMQ 实战 集群监控平台搭建

    RocketMQ 实战 集群监控平台搭建 概述 RocketMQ有一个对其扩展的开源项目incubator-rocketmq-externals,这个项目中有一个子模块叫rocketmq-consol ...

  9. 3d饼图 vue_Vue+Echarts构建可视化大数据平台实战项目分享(附源码)(上)

    前言 分享之前我们先来普及一下什么是数据可视化?数据可视化可以把数据从冰冷的数字转换成图形,揭示蕴含在数据中的规律和道理.数据可视化通俗来说就是:数据的展示.处理和分析.目的是借助于图形化手段,清晰有 ...

最新文章

  1. “12306” 是如何支撑百万 QPS 的?
  2. qlabel 边加载边更新_盘点十四款国产进口边三轮,挎斗子摩托车,售价从1万至60多万...
  3. 转移地址在内存中的jmp指令 检测点9.1
  4. NYOJ 229 工程 二分+dp检验
  5. ABB机器人 系统参数配置
  6. 一篇文章学习Python中的多进程
  7. sql 一列中平均应发工资_劳动者的工资标准,应如何认定?
  8. 实用c语言程序设计教材,实用C语言程序设计
  9. 黄刘生--数据结构--答案 2
  10. javascript 遍历数组的常用方法(迭代、for循环 、for… in、for…of、foreach、map、filter、every、some,findindex)
  11. 五种食物可以吃掉黑眼圈
  12. 唯品会密码JS解密与python模拟登录
  13. 按键精灵--函数的介绍
  14. matlab中巴特沃斯滤波器的使用
  15. 疫情过后,35岁老程序员年后第一天上班被公司劝退,该何去何从?
  16. win10系统C盘存储使用优化操作教程
  17. pdn阻抗测试_毫欧级电源分配网络PDN的输出阻抗和传输阻抗测量
  18. Ant Design Vue 文件上传自定义按钮和文件列表位置
  19. 【实战模拟】下载安装并配置虚拟kali Linux 和 OWASP Broken Web Apps 靶机
  20. 全网最全的权限系统设计方案

热门文章

  1. quasar+node实现一个简单的群聊天
  2. 创建角色、ansible-galaxy的简单使用
  3. 微信消息推送神器pushplus介绍,让消息推送更简单
  4. h3c路由器修改ssh登录密码
  5. 2021红亚杯-Python编程线上挑战赛前20题(含自己的代码)
  6. 从(新浪)motan看RPC框架设计
  7. 软件测试面试技巧 这么准备,拿下心仪offer不是问题
  8. c语言用一维数组存储数据,C语言一维数组入门教程
  9. latent_3d_points代碼付現:Learning Representations and Generative Models For 3D Point Clouds
  10. 个体值0和31差多少攻击_口袋妖怪努力值、个体值、觉醒力量讲解