项目介绍和环境配置和数据库表的设计
-
项目介绍
-
系统具有完整的用户登录注册功能以及找回密码功能,拥有完整的个人中心
-
个人中心:修改头像,修改密码,修改邮箱,可以看到我的课程以及我的收藏,可以删除收藏,我的消息
-
导航栏:公开课,授课老师,授课机构,全局搜索
-
点击公开课: 课程列表,排序-搜索.热门课程推荐,课程的分页
-
点击课程: 课程详情页中对课程进行收藏,取消收藏.富文本展示课程内容
-
点击开始学习: 课程的章节信息,课程的评论信息,课程资源的下载链接
-
点击授课讲师–>授课讲师列表页,对讲师进行人气排序以及分页,右边有讲师排行榜。
-
点击讲师的详情页面–> 对讲师进行收藏和分享,以及讲师的全部课程。
-
导航栏: 授课机构有分页,排序筛选功能。
-
机构列表页右侧有快速提交我要学习的表单。
-
点击机构–> 左侧:机构首页,机构课程,机构介绍,机构讲师。
-
后台管理系统可以切换主题。左侧每一个功能都有列表显示, 增删改查,筛选功能。
-
课程列表页可以对不同字段进行排序。选择多条记录进行删除操作。
-
课程列表页:过滤器->选择字段范围等,搜索,导出csv,xml,json。
-
课程新增页面上传图片,富文本的编辑。时间选择,添加章节,添加课程资源。
-
日志记录:记录后台人员的操作
-
前台和后台功能介绍
-
项目的完整的开发流程
主要用用到的技术知识点
- 数据库设计和xadmin搭建后台管理系统任务
通过业务分析设计django的每个app,设计app下的model。设计外键关系,通过django的migrate设计生成数据表。
然后将这些model注册到xadmin当中。为每个model配置搜索,过滤字段,以及列表页的显示字段。配置xadmin的主题选择功能。
- 系统功能模块实现任务
实现所有后台功能 & 面试中经常被提及的web开发知识。
几乎所有的django常用模块:
-
settings配置
-
url配置
-
view的书写
-
model设计
-
model和modelform的使用
-
templates模板使用
-
django常用的内置模块
-
web系统知识以及网络安全任务
防止一些攻击问题 -
sql注入
-
xss攻击
-
crsf攻击
这些攻击的原理以及防护措施
xadmin的扩展知识
掌握更多的定制功能:
- 权限管理
- 权限配置
- 权限,用户,组之间的关系
- xadmin常用插件
- 如何自定义xadmin插件
- xadmin的富文本编辑功能
- xadmin的excel的导入功能
还会用到一些开源的django开源库
-
开发环境的搭建
1. virtualenv的安装和配置
virtualenv介绍
每个应用可能需要各自一套独立的python运行环境.virtualenv就是为了给每个应用创建一套隔离的Python运行环境.
virtualenv的优点:
安装virtualenv
进入cmd
pip install virtualenv
virtualenvwrapper安装
pip install virtualenvwrapper-win
创建虚拟环境
创建之前,先加一个WORKON_HOME的环境变量
- 退出激活状态
deactivate
- 查看有哪些虚拟环境
workon
- 直接进入虚拟环境
workon xxx
- 创建虚拟环境
mkvirtualenv mx_online
- 通过指定的python创建虚拟环境
mkvirtualenv -p C:\Python36\python.exe mx_online
进入虚拟环境,然后安装相应的必备的依赖包
进入虚拟环境安装相关的依赖包
pip install -r C:\Envs\requirements.txt
requirements.txt
Django==1.11.6
django-crispy-forms==1.7.2
django-formtools==2.1
django-import-export==1.0.1
django-pure-pagination==0.3.0
django-ranged-response==0.2.0
django-simple-captcha==0.5.6
et-xmlfile==1.0.1
future==0.16.0
httplib2==0.9.2
jdcal==1.4
odfpy==1.3.6
openpyxl==2.5.6
Pillow==5.2.0
pytz==2018.5
PyYAML==3.13
six==1.11.0
tablib==0.12.1
unicodecsv==0.14.1
xlrd==1.1.0
xlwt==1.3.0
安装完毕之后,创建一个Django项目,名字为MxOnline, 环境继承自刚才的虚拟环境
image.png将项目关联到github,创建远程仓库
2.Django-app 设计
数据库设计
根据app设计models
授课机构提供讲师录制课程,学院完成在线学习.
- 全局头部: 用户消息&个人中心:没有登录时,就是登录注册
- 对于公开课,授课老师,授课机构进行搜索
- 轮播图,课程,机构,页脚
- 公开课:分页公开课,右边热门推荐
- 点进课程:课程详情页.详情:后台富文本.右边是课程结构的介绍.收藏或学习
- 章节信息 & 课程资源下载 & 评论
- 授课讲师: 授课讲师列表页,讲师排行榜.分页
- 点进讲师:看到课程
- 授课机构:类别筛选,机构性质,所在地区 & 排序.用户提交表单,我要学习,机构排名
- 个人中心:修改密码,修改头像,个人信息,我的课程,我的收藏,我的消息
app大致分为4个模块
users - 用户模块
course - 课程模块
organization - 机构教师模块
operation - 用户操作模块
3.setting.py设置
-
数据库的配置
首先确保你的电脑里有mysql应用,然后安装pymysql,分为两个步骤:
pip install pymysql
# 然后setting.py中写入以下代码
image.png
还要在MxOnline/init.py中,声明运用pymysql
import pymysql
pymysql.install_as_MySQLdb()
进行数据库初始化,创建数据库表.注意,之前必须在数据里创建上面设置里面对应的表名mxonline
点击tools
下的Run manage.py Task 或者ctrl + alt + r打开manage.py操作面板
makemigrations
migrate
将页面显示的语言设置为中文,并且时间设置为上海时间
# 语言改为中文
LANGUAGE_CODE = 'zh-hans'
# 时区改为上海
TIME_ZONE = 'Asia/Shanghai'
USE_I18N = True
USE_L10N = True
# 数据库存储使用时间,True时间会被存为UTC的时间
USE_TZ = False
然后运行就可以看到这个界面
-
3.自定义userprofile
在manage.py Task下创建app users
startapp users
编辑我们的model设计user表
系统自动生成的user表如下:
个人中心页面:
可以看到我们还需要:
- 昵称: nickname
- 生日:birthday
- 性别:gender
User表的自定方法,如果既想保留原有的字段,又想有新字段.
可以在models.py中创建UserProfile 继承自AbstractUser,然后添加新的属性字段.
然后在setting.py中重载AUTH_USER_MODEL
# 此处重载是为了使我们的UserProfile生效
AUTH_USER_MODEL = "users.UserProfile"
models.py中添加如下代码
from django.contrib.auth.models import AbstractUser
from django.db import models
class UserProfile(AbstractUser):
# 自定义的性别选择规则
GENDER_CHOICES = (
('male', '男'),
('female', '女')
)
# 昵称
nick_name = models.CharField(max_length=50, verbose_name='昵称', default='')
# 生日可以为空,null=True是针对数据库的,而blank=True是针对表单的.
# 表示该字段在数据库中可以为空,同时提交表单的时候可以,该字段可以不填.
birthday = models.DateField(null=True, blank=True, verbose_name='生日')
# 性别,只能是男或者女.默认是女
gender = models.CharField(max_length=6, choices=GENDER_CHOICES, default='female', verbose_name='性别')
# 地址
address = models.CharField(max_length=100, default='', verbose_name='地址')
# 电话
mobile = models.CharField(max_length=11, null=True, blank=True, verbose_name='电话')
# 头像 默认使用default.png
image = models.ImageField(upload_to='image%Y%m',
default='image/default.png',
max_length=100,
verbose_name='头像')
class Meta:
verbose_name = '用户信息'
verbose_name_plural = verbose_name
def __str__(self):
return "<UserProfile: >{}".format(self.username)
在setting.py中注册app
INSTALL_APPS = [
...
'users'
]
因为Image字段需要用到pillow所以需要安装该库
pip install pillow
然后执行
makemigrations
migrate
如果出现以下错误
django.db.migrations.exceptions.InconsistentMigrationHistory: Migration
admin.0001_initial is applied before its dependency users.0001_initial on
database 'default'
解决方案:
删除数据库中 除了auth_user的其他表
删除表的时候,可能会遇到删不掉的情况,就先删除其他的,带有外键关联的表,需要先删除有外键的表
然后执行命令:
makemigrations
migrate
makemigrations users
migrate users
共十一张表
-
4.user models.py的设计
创建另外三个app,manage.py Task下
startapp courses
startapp organization
startapp operation
循环引用:
设计app时每个app都有model
如图:我们在user中定义usercourse记录用户学习的课程.会有两个外键:user和course
我们就会import Courses.models
如果用户对课程的评论放到Courses.models当中.评论我们需要保存相应的用户.我们就会import User.models
两个Models互相引用,就会出现循环导入,a和b相互调用,造成等待.
解决循环引用: 分层设计
目前已有app:users courses oranization operation
另外一个app operation高于这些app的层级.上一层的app可以import下层的app
user表中还需要添加的(前提是这些功能比较独立,不会和其他的模块产生import,这些顶层的model可以放到user的models.py中)
- EmailVerifyRecord - 邮箱验证码
- PageBanner - 轮播图
users/models.py
# 邮箱验证码
class EmailVerifyRecord(models.Model):
SEND_CHOICES = (
('register', '注册'),
('forget', '找回密码'),
('update_email', '修改邮箱'),
)
code = models.CharField(max_length=20, verbose_name='验证码')
email = models.EmailField(max_length=50, verbose_name='邮箱')
# 验证码的用途,注册和找回密码的时候都可以使用,所以要分类
send_type = models.CharField(choices=SEND_CHOICES, max_length=20, verbose_name='验证码类型')
# 这里的now得去掉(),不去掉会根据编译时间。而不是根据实例化时间。
send_time = models.DateTimeField(default=datetime.now, verbose_name='发送时间')
class Meta:
verbose_name = '邮箱验证码'
verbose_name_plural = verbose_name
def __str__(self):
return "<EmailVerifyRecord: >{}".format(self.code)
class Banner(models.Model):
title = models.CharField(max_length=100, verbose_name='标题')
# 保存到数据库的时候存储的是url地址
image = models.ImageField(max_length=100, upload_to='banner/%Y/%m', verbose_name='轮播图')
url = models.URLField(max_length=200, verbose_name='访问地址')
# 控制轮播图的顺序
index = models.IntegerField(default=100, verbose_name='顺序')
add_time = models.DateTimeField(default=datetime.now, verbose_name='添加时间')
class Meta:
verbose_name = '轮播图'
verbose_name_plural = verbose_name
def __str__(self):
return "{0}(位于第{1}位)".format(self.title, self.index)
Courses/models.py的编写
课程本身需要一张表
点进去之后
- 点进去之后开始学习
- 课程基本信息需要一张表,章节表与课程表存在多对一的关系(一个课程对应多个章节)
- 章节表中:章节的名称,章节与食品(一个章节对应多个视频)
结构: 课程本身 -- (一对多) > 章节 (一对多) -> 视频信息
资源下载放在课程里面的,一个课程对应多个资源.
共四张表:
课程本身(一对多)章节 -> (一对多) -> 视频信息 & 资源表
课程表的编写,注意他们之间的表的对应关系
from datetime import datetime
from django.db import models
# 课程信息表
class Course(models.Model):
DegreeChoices = (
('cj', '初级'),
('zj', '中级'),
('gj', '高级')
)
name = models.CharField(max_length=50, verbose_name='课程名称')
desc = models.CharField(max_length=300, verbose_name='课程描述')
# 后期会替换为富文本的模式
detail = models.TextField(verbose_name='课程详情')
degree = models.CharField(choices=DegreeChoices, max_length=2)
learn_time = models.IntegerField(default=0, verbose_name='学习时长(分钟数)')
students = models.IntegerField(default=0, verbose_name='学习人数')
fav_nums = models.IntegerField(default=0, verbose_name='收藏人数')
image = models.ImageField(upload_to='courses/%Y/%m', max_length=100, verbose_name='封面图')
click_nums = models.IntegerField(default=0, verbose_name='点击数')
add_time = models.DateTimeField(default=datetime.now, verbose_name='添加事件')
class Meta:
verbose_name = '课程'
verbose_name_plural = verbose_name
def __str__(self):
return self.name
# 章节表 课程和章节的对应关系 (一对多)->(课程对章节)
class Lesson(models.Model):
# 外键关联
course = models.ForeignKey(Course, verbose_name='课程')
name = models.CharField(max_length=100, verbose_name='章节名')
add_time = models.DateTimeField(default=datetime.now, verbose_name='添加时间')
class Meta:
verbose_name = '章节'
verbose_name_plural = verbose_name
def __str__(self):
return '<<{0}>>课程的章节{1}'.format(self.course, self.name)
# 视频表
class Video(models.Model):
lesson = models.ForeignKey(Lesson, verbose_name='章节')
name = models.CharField(max_length=100, verbose_name='视频名')
add_time = models.DateTimeField(default=datetime.now, verbose_name='添加时间')
class Meta:
verbose_name = '视频'
verbose_name_plural = verbose_name
def __str__(self):
return "<<{0}>>章节的视频{1}".format(self.lesson, self.name)
# 课程资源表
class ResourceCourse(models.Model):
# course相关
course = models.ForeignKey(Course, verbose_name='课程')
name = models.CharField(max_length=100, verbose_name='名称')
download = models.FileField(upload_to='course/resource/%Y/%m', max_length=100, verbose_name='资源名称')
add_time = models.DateTimeField(default=datetime.now, verbose_name='添加时间')
class Meta:
verbose_name = '课程资源'
verbose_name_plural = verbose_name
def __str__(self):
return "<<{0}>> 课程的资源: {1}".format(self.course, self.name)
通过Structure可以看到我们刚才设计了四张表
organization(课程机构表)的编写 organization/models.py
课程是属于机构,机构有机构类别,城市等字段.讲师实体.
我要学习的提交表单会与用户关联,存放在机构.
点击具体的课程:
其中课程数,学习人数可以动态统计.机构地址,机构经典课程.
机构讲师,机构课程可以通过外键获取到,不保存到机构中
对应的models.py如下
from datetime import datetime
from django.db import models
class CityDict(models.Model):
name = models.CharField(max_length=20, verbose_name='城市')
desc = models.CharField(max_length=200, verbose_name='描述')
add_time = models.DateTimeField(default=datetime.now)
class Meta:
verbose_name = '城市'
verbose_name_plural = verbose_name
def __str__(self):
return self.name
class CourseOrg(models.Model):
name = models.CharField(max_length=50, verbose_name='机构名称')
desc = models.TextField(verbose_name='机构描述')
click_nums = models.IntegerField(default=0, verbose_name='点击数')
fav_nums = models.IntegerField(default=0, verbose_name='收藏')
image = models.ImageField(upload_to='org/%Y/%m', verbose_name='封面图')
address = models.CharField(max_length=150, verbose_name='机构地址')
# 城市外键
city = models.ForeignKey(CityDict, verbose_name='所在城市')
add_time = models.DateTimeField(default=datetime.now, verbose_name='添加时间')
class Meta:
verbose_name = '课程机构'
verbose_name_plural = verbose_name
def __str__(self):
return '课程机构: {}'.format(self.name)
# 教师信息表
class Teacher(models.Model):
# 外键,一个机构可以对应多个老师
org = models.ForeignKey(CourseOrg, verbose_name='所属机构')
name = models.CharField(max_length=50, verbose_name='教师名')
work_years = models.IntegerField(default=0, verbose_name='工作年限')
work_company = models.CharField(max_length=50, verbose_name='就职公司')
work_position = models.CharField(max_length=100, verbose_name='公司职位')
points = models.CharField(max_length=50, verbose_name='教学特点')
click_nums = models.IntegerField(default=0, verbose_name='点击数')
fav_nums = models.IntegerField(default=0, verbose_name='收藏数')
add_time = models.DateTimeField(default=datetime.now, verbose_name='添加时间')
class Meta:
verbose_name = '教师'
verbose_name_plural = verbose_name
def __str__(self):
return '[{0}]的教师: {1}'.format(self.org, self.name)
我们可以看到,organization/models.py中一共具有三张表
operation/models.py设计
分析需要哪些表:
- 用户可以提交我要学习的个人需求
- 学员的课程评论信息
- 收藏:可以收藏公开课,授课讲师,授课机构,用户消息提醒.
- 个人中心:我的课程, 说明用户和课程之间的学习关系也需要保存.
from datetime import datetime
from django.db import models
# 用户我要学习表单,用户咨询
from courses.models import Course
from users.models import UserProfile
class UserAsk(models.Model):
name = models.CharField(max_length=20, verbose_name='姓名')
mobile = models.CharField(max_length=11, verbose_name='手机')
course_name = models.CharField(max_length=50, verbose_name='课程名')
add_time = models.DateTimeField(default=datetime.now, verbose_name='添加时间')
class Meta:
verbose_name = '用户咨询'
verbose_name_plural = verbose_name
def __str__(self):
return '用户: {0} 手机号: {1}'.format(self.name, self.mobile)
# 用户对于课程的评论
class CourseComments(models.Model):
# 会涉及到两个外键,1.用户 2.课程 import进来
course = models.ForeignKey(Course, on_delete=models.CASCADE, verbose_name='课程')
user = models.ForeignKey(UserProfile, on_delete=models.CASCADE, verbose_name='用户')
comments = models.CharField(max_length=250, verbose_name='评论')
add_time = models.DateTimeField(default=datetime.now, verbose_name='评论时间')
class Meta:
verbose_name = '课程评论'
verbose_name_plural = verbose_name
def __str__(self):
return '用户{0}对于{1}的评论: '.format(self.user, self.course)
# 用户对于课程,机构,讲师的收藏
class UserFavorite(models.Model):
# 选择收藏的类别
TYPE_CHOICES = (
(1, '课程'),
(2, '课程机构'),
(3, '讲师')
)
user = models.ForeignKey(UserProfile, verbose_name='用户')
fav_id = models.IntegerField(default=0, verbose_name='数据id')
fav_type = models.IntegerField(choices=TYPE_CHOICES, default=1, verbose_name='收藏类型')
add_time = models.DateTimeField(default=datetime.now, verbose_name='添加时间')
class Meta:
verbose_name = '用户收藏'
verbose_name_plural = verbose_name
def __str__(self):
return '用户({0})收藏了{1} '.format(self.user, self.fav_type)
# 用户消息表
class UserMessage(models.Model):
# user为0的时候,发送给所有.
user = models.IntegerField(default=0, verbose_name='接收用户')
message = models.CharField(max_length=500, verbose_name='消息内容')
has_read = models.BooleanField(default=False)
add_time = models.DateTimeField(default=datetime.now, verbose_name='添加时间')
class Meta:
verbose_name = '用户消息'
verbose_name_plural = verbose_name
def __str__(self):
return '用户({0})接收了{1} '.format(self.user, self.message)
# 用户课程表
class UserCourse(models.Model):
# 会涉及两个外键: 1.用户 2.课程
course = models.ForeignKey(Course,on_delete=models.CASCADE,verbose_name='课程')
user = models.ForeignKey(UserProfile,on_delete=models.CASCADE,verbose_name='用户')
add_time = models.DateTimeField(default=datetime.now,verbose_name='添加时间')
class Meta:
verbose_name = '用户课程'
verbose_name_plural = verbose_name
def __str__(self):
return '用户({0})学习了{1} '.format(self.user, self.course)
到这里我们所有的models都设计完毕.operation/models.py
settings.py中添加配置app
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
# 注册app
'users',
'organization',
'courses',
'operation',
]
数据表的生成以及apps目录的建立
打开manage.py 的Task
makemigrations
migrate
生成如下的表:
把我们的四个app放到一个文件夹下.
新建Python的package:apps
然后将四个app拖进去,注意不要选择下面的选项
然后将apps包右键mark为sourceRoot.根目录下找不到,会去apps目录下搜索.
但是这时候cmd下还是会报错
解决方法:
将apps设置到我们的系统搜索目录之下